This file is indexed.

/usr/share/psychtoolbox-3/PsychTests/DaqTest.m is in psychtoolbox-3-common 3.0.9+svn2579.dfsg1-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

   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
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
function DaqTest
% DaqTest
%
% DaqTest assesses the Daq Toolbox, which provides communication with a
% particular USB data acquisition device (daq): the USB-1208FS made by
% Measurement Computing (see URL below). This daq costs $150 and offers "50
% kHz" input and output 12-bit sampling of analog voltages (8 in, 2 out)
% and 16 digital i/o lines, with signals brought out to screw terminals.
% ("50 kHz" is a theoretical upper limit: as of 18 April 2005 we attain 2
% kHz.) The USB-1208FS is the size of a wallet and is powered through its
% USB cable. The Daq Toolbox gives you complete control of it from within
% Matlab, via the PsychHID extension.
%
% DaqTest assesses all the functions provided by the USB-1208FS firmware.
% (Some risky tests, below, have been turned off, but can be re-enabled by
% the adventurous user.) DaqFunctions gives a brief description of every
% function.
%
% NOT RESPONDING? If PsychHID is not responding, e.g. after unplugging and 
% re-plugging the USB connector of your device, try quitting and restarting
% MATLAB. We find that this reliably restores normal communication. 
%
% web http://www.http://www.measurementcomputing.com/cbicatalog/directory.asp?dept_id=403 -browser;
% web http://psychtoolbox.org/daq.html -browser;
% See also: Daq, DaqFunctions, DaqPins,PsychHIDTest,PsychHID,PsychHardware,
% DaqDeviceIndex, DaqDIn, DaqDOut, DaqAIn, DaqAOut, DaqAInScan, DaqAOutScan

% 3/21/05 dgp Denis Pelli wrote it.
% 3/28/05 dgp Corrected reportID and reportBytes.
% 3/30/05 dgp More error checking.
% 3/31/05 dgp Added the rest of the functions.
% 4/2/05  dgp The input functions now work, for the first time.
% 4/15/05 dgp Polished.
% 4/15/05 dgp Merged arguments in calls to DaqAOutScan and DaqAInScan.
% 4/25/05 dgp Nearly eliminated crash associated with CLEAR MEX.
% 4/26/05 dgp Fixed DaqAInScan to return sensible results.
% 8/26/05 dgp Incorporated bug fix for compatibility with Mac OS X Tiger 
%             suggested by Maria Mckinley <parody@u.washington.edu>. The reported
%             number of outputs of the USB-1208FS has changed in Tiger.
%             http://groups.yahoo.com/group/psychtoolbox/message/3614
% 11/xx/07 - 
%  1/xx/08 mpr  Instituted various fixes to get this to work for a USB-1608FS
%                   in Leopard
% 05/11/09 mk Add if isempty(FinalStatus) in line 444 and later to catch
%             empty returns from DaqGetStatus.

debugging=0; % Used by dgp to track down a crash in PsychHID.

% Do we have a USB-1208FS daq? Each such box will present itself as four
% HID "devices" sharing the same serial number.  For 1608FS, there may be 5, 6,
% or 7 devices.  Don't know why the variation...  Should be 7...  Most commands
% will work even if only five interfaces are found, but the most important
% commands -- the ones that read digitized analog signals -- require all seven
% interfaces unless you're willing to lose some data.  So we'll try to make sure
% all are found before continuing.
daq=DaqDeviceIndex([],0);

if isempty(daq)
  % check again because user might have run PsychHID('Devices') and then plugged
  % in the daq.  This should fix that.
  clear PsychHID;
  daq = DaqDeviceIndex([],0);
end

devices=PsychHID('Devices');
fprintf('\n');
switch length(daq)
  case 0,
    fprintf('Sorry. Couldn''t find any USB-1208FS, -1408FS, or -1608FS boxes connected to your computer.\n');
    return;
  case 1,
    fprintf('Yay. I found a %s daq!  Serial number is: %s\n',devices(daq).product,devices(daq).serialNumber);
    if strcmp(devices(daq).product(5:6),'16')
      eval(['[' sprintf('AllSNs{%d},',1:(length(devices)-1)) 'AllSNs{' int2str(length(devices)) '}] = deal(devices.serialNumber);']);
      NumInterfaces = length(cell2mat(strfind(AllSNs,devices(daq).serialNumber)));
      if NumInterfaces ~= 7
        ConfirmInfo(sprintf('Found %d interfaces where there should be 7.  Run "help DaqReset" for suggestions; then re-run "DaqTest"',NumInterfaces));
        return;
      end
    end
    numTries = 0;
    TheLEDBlinked = 0;
    while ~TheLEDBlinked
      ConfirmInfo('Direct your attention to the LED on the device and then click the "okay" button here:');
      err=DaqBlinkLED(daq);
      if err.n
        fprintf(['\nUh oh... there was a problem when I told your device to blink its LED.\n' ...
                 'I haven''t seen this before, so I don''t know what''s going on.  This is\n' ...
                 'what PsychHID told me about the problem, though:\n\n']);
        err
        fprintf('\nI''ll let you try to fix the problem and then come back to me.  Bailing now!\n\n');
        return;
      end
      TheLEDBlinked = TwoStateQuery('Did the LED just blink for you?');
      if TheLEDBlinked < 0
        ConfirmInfo('Please click yes or no... do not close the window any other way!');
        TheLEDBlinked = TwoStateQuery('Did the LED blink for you earlier?');
        if TheLEDBlinked < 0
          ConfirmInfo('You do not seem to play well with others.  I am quitting on you!');
          return;
        end
      end
      numTries = numTries+1;
      if numTries > 1 & ~TheLEDBlinked
        ConfirmInfo('It should have blinked.  Since it didn''t and there were no obvious errors I will bail and let you work on it.');
        return;
      end
    end
  case 2,
    fprintf('Yay. You have two daqs!');
    numTries = 0;
    TheLEDBlinked = 0;
    while ~TheLEDBlinked
      if strcmp(devices(daq(1)).product(5:6),'16')
        eval(['[' sprintf('AllSNs{%d},',1:(length(devices)-1)) 'AllSNs{' int2str(length(devices)) '}] = deal(devices.serialNumber);']);
        NumInterfaces = length(cell2mat(strfind(AllSNs,devices(daq(1)).serialNumber)));
        if NumInterfaces ~= 7
          ConfirmInfo(sprintf('Found %d interfaces where there should be 7.  Run "help DaqReset" for suggestions; then re-run "DaqTest"',NumInterfaces));
          return;
        end
      end
      fprintf('\nI''m about to try device with serial number: %s\n',devices(daq(1)).serialNumber);
      ConfirmInfo('Look at the LED on the daq you want to test and then click this button:');
      err=DaqBlinkLED(daq(1));
      if err.n
        fprintf(['\nUh oh... there was a problem when I told your first device to blink its LED.\n' ...
                 'This is the error message I received:\n\n']);
        err

        fprintf('\nI will move on to the second one anyways and hope for the best.\n');
      end

      TheLEDBlinked = TwoStateQuery('Did the LED blink on the device you want to test?');
      if TheLEDBlinked < 0
        fprintf('\nYou should have clicked "Yes" or "No".  I am taking your response as a "No".\n');
        TheLEDBlinked = 0;
      end
      if TheLEDBlinked
        daq = daq(1);
        break;
      else
        if strcmp(devices(daq(2)).product(5:6),'16')
          eval(['[' sprintf('AllSNs{%d},',1:(length(devices)-1)) 'AllSNs{' int2str(length(devices)) '}] = deal(devices.serialNumber);']);
          NumInterfaces = length(cell2mat(strfind(AllSNs,devices(daq(2)).serialNumber)));
          if NumInterfaces ~= 7
            ConfirmInfo(sprintf('Found %d interfaces where there should be 7.  Run "help DaqReset" for suggestions; then re-run "DaqTest"',NumInterfaces));
            return;
          end
        end
        fprintf('I''m about to try device with serial number: %s\n',devices(daq(2)).serialNumber);
        Confirm('Look again at the LED on the device you want to test and then click this button:');
        err=DaqBlinkLED(daq(2));
        if err.n
          fprintf(['\nUh oh... there was a problem when I told your second device to blink its LED.\n' ...
                   'This is the error message I received:\n\n']);

          err              
        end
        TheLEDBlinked = TwoStateQuery('Did the LED blink on the device you want to test?');
        if TheLEDBlinked < 0
          fprintf('\nYou should have clicked "Yes" or "No".  I am taking your response as a "No".\n');
          TheLEDBlinked = 0;
        end
        if TheLEDBlinked
          daq = daq(2);
          break;
        end
      end
      numTries = numTries+1;
      if numTries > 1 & ~TheLEDBlinked
        ConfirmInfo('I don''t know why this didn''t work.  I hope you do because I am bailing!');
        return;
      end
    end % while ~TheLEDBlinked
  otherwise,
    fprintf('Yay. You have %d daqs (the first one is a %s): \n',length(daq),devices(daq(1)).product);
    numTries = 0;
    TheLEDBlinked = 0;
    while ~TheLEDBlinked
      for k=1:length(daqs)
        if strcmp(devices(daq(k)).product(5:6),'16')
          eval(['[' sprintf('AllSNs{%d},',1:(length(devices)-1)) 'AllSNs{' int2str(length(devices)) '}] = deal(devices.serialNumber);']);
          NumInterfaces = length(cell2mat(strfind(AllSNs,devices(daq(k)).serialNumber)));
          if NumInterfaces ~= 7
            ConfirmInfo(sprintf('Found %d interfaces where there should be 7.  Run "help DaqReset" for suggestions; then re-run "DaqTest"',NumInterfaces));
            return;
          end
        end
        fprintf('About to test device %d, serial number: %s\n',k,devices(daq(k)).serialNumber);
        ConfirmInfo('Look at the LED on the device you want to test and click "Okay" when ready');
        err=DaqBlinkLED(daq(k));
        if err.n
          fprintf('Uh-oh... there was an error when I tried to blink the LED on device %d.  It was:\n\n',k);
          err
          fprintf('I will proceed anyways...');
        end
        TheLEDBlinked = TwoStateQuery('Did the LED blink on the device you wanted to test?');
        if TheLEDBlinked < 0
          fprintf('You should have clicked "yes" or "no".  I am taking your response as "no"');
          TheLEDBlinked = 0;
        end
        if TheLEDBlinked
          daq = daq(k);
          break;
        end
        if numTries > 1
          ConfirmInfo('I tried each LED twice...  I am giving up now.  Sorry!');
          return;
        end
        numTries = numTries+1;
      end % for k=1:length(daqs)
    end % while ~TheLEDBlinked
end % switch length(daq)

if strcmp(devices(daq).product(5:6),'16')
  Is1608=1;
else
  Is1608=0;
end

% After passing through the above code, daq should be a scalar.  References to
% it as "daq(1)" are a legacy of prior versions.  Not deemed worth fixing.  --
% mpr

if debugging
  % line numbering is... well, I think this used to be line 67...
% 	fprintf('TestClearMex once crashed at line 67.\n');
    TestClearMex(daq);
end

% fprintf(['\n** NOT RESPONDING? If your %s is not responding, try quitting and\n'...
%     '** restarting MATLAB. Denis found that this reliably restored normal\n'...
%     '** communication for his device.\n'],devices(daq(1)).product);
if strcmp(devices(daq(1)).product,'USB-1208FS') | strcmp(devices(daq(1)).product,'PMD-1208FS') | strcmp(devices(daq(1)).product,'USB-1408FS')  
  fprintf(['\n'...
      '** WIRING THE PINS OF THE USB-1208FS (and presumably -1408FS)\n'...
      '**    For the analog i/o test, please connect both channels of analog\n'...
      '** output to the first two channels of differential analog input:\n'...
      '** Connect pin 1 to 13, 2 to 12, 4 to 14, and 5 to 12.\n'...
      '**    If you''ve got one, you may want to attach a speaker or oscilloscope\n'...
      '** to analog output channel 0 (pin 13) and analog ground (pin 12). \n'...
      '**    Or you may want to connect to bit 0 of digital output port A (pin 21) \n'...
      '** and digital ground (pin 29).\n']);
elseif strcmp(devices(daq(1)).product,'USB-1608FS')
   fprintf(['\n** If you want to run all the tests we have here, you should connect analog\n' ...
            '** port 0 (pin 1) to the first bit of the digital port (pin 21).  If you would\n' ...
            '** like to test your counter, you should also connect pin 21 to the counter\n' ...
            '** terminal (pin 38).  Measurement Computing recommends that you ground any\n' ...
            '** analog ports that you are not using.  To follow that advice, connect pin 3\n' ...
            '** to pin 4, pin 5 to pin 6, pin 7 to pin 8, pin 9 to pin 10, pin 11 to pin 12,\n' ...
            '** pin 13 to pin 14, and pin 15 to pin 16.\n\n']);
else
  fprintf('Your device has not been tested with this toolbox.  You should verify the wiring and edit DaqTest to comply with it.\n');
  return;
end

ConfirmInfo(['A lot of information will be written to the Matlab command window.  ' ...
             'You can ignore most of it, but you should look at the command window now.']);

drawnow;

% The USB-1208FS is a composite device. It has four interfaces (0,1,2,3)
% which are each represented as a device in the list returned by
% PsychHID('Devices'). In calling the Daq functions, the user supplies us
% only the device index "device" corresponding to interface 0 of the
% desired USB-1208FS. However, the reports containing the samples arrive on
% interfaces 1,2,3. As returned by PsychHID('Devices'), interface i is at
% device-i, and we proceed on that basis after doing a quick check to
% confirm our assumption. However, to be platform-independent, it would be
% better to actually find all four device interfaces and confirm their
% interface numbers. USB Probe reports interface numbers, but, as far as I
% can tell, Apple's HID Explorer and our PsychHID do not return this 
% information. However, PsychHID('Devices') does report the number of outputs: 
% the USB-1208FS interface 0 has 229 (pre-Tiger) 70 (Tiger) outputs, interface 1
% has 65 (pre-Tiger) 1 (Tiger) outputs, and interfaces 2 and 3 have zero 
% outputs.  I have no idea why the number of outputs changed with the arrival of
% Mac OS X Tiger.
% 
% The USB-1608FS under Leopard behaves quite differently.  It has seven
% interfaces, no six... no five interfaces... so far I've had the system come
% up each of those ways and in that order...  In all cases, though, all but the 
% last (read highest index in the array returned by "PsychHID('Devices')") of 
% the interfaces have had 1 input, no outputs, and one collection.  The last
% interface (I am currently presuming interface 0) has 18 inputs, 66 outputs, 
% and 1 collection for a total of 85 totalElements.  I tried Tiger once and 
% found six interfaces.  Then I rebooted in Leopard again and found six 
% interfaces again as well.  Only difference seemed to be that Leopard 
% recognized the Apple Studio Display in my call to PsychHID, and Tiger didn't.
devices=PsychHID('Devices');
for d=daq 
  ok= (d-3>=1 && (devices(d-1).outputs==65 || devices(d-1).outputs==1)) || (d+3<=length(devices) && (devices(d+1).outputs==65 || devices(d+1).outputs==1));
  if devices(d).outputs<70 && ok
    fprintf(['If you have a 1408FS, you should just have been given a message\n' ...
             'suggesting some changes in the software.  If you are seeing this \n' ...
             'message, you are probably the first person to test a 1408 with the\n' ...
             'daq toolbox.\n']);
    error(sprintf('Invalid device, not the original USB-1208FS or USB-1608FS.'));
  end
end

if debugging
    TestClearMex(daq);
end

% Denis originally did not test the memory read and write functions because he
% was afraid of messing up his firmware.  However, since this was one of the
% first sets of functions from which I got interpretable test results, I added
% some safeguards to DaqMemWrite and added tests of the functions here. -- mpr
fprintf('\nTesting my ability to read and write your daq device''s EEPROM...');

[TheOriginalData,TheErrors] = DaqMemRead(daq(1),512,59);
MemoryReadError = 0;
for k=1:length(TheErrors)
  if TheErrors(k).n
    MemoryReadError = 1;
    TheErrors(k)
  end
end

if MemoryReadError
  fprintf(['\nYou should have just been told of at least one error that occurred when I\n' ...
           'tried to read the EEPROM of your daq device.  Since it failed this test, I\n' ...
           'am aborting.  Sorry things didn''t work out...\n\n']);
  return;
end

MemWriteTestData = 1:59;

fprintf('\nMemory was apparently read successfully...');
err=DaqMemWrite(daq(1),512,MemWriteTestData);
if err.n
  fprintf(['\nUh oh... an error occurred when I tried to write to the EEPROM of your daq\n' ...
           'device.  Since that test failed, I am aborting.  I hope that I have not screwed\n' ...
           'up the memory of your device...  In any case, I am bailing out now.  Good\n' ...
           'luck fixing things!  What I was told was:\n\n']);
  err
  return;
end

fprintf('\nMemory was apparently written successfully...');

[TheWrittenData,TheErrors] = DaqMemRead(daq(1),512,59);
MemoryReadError = 0;
for k=1:length(TheErrors)
  if TheErrors(k).n
    MemoryReadError = 1;
    TheErrors(k)
  end
end

if MemoryReadError
  fprintf(['\nUh oh... I spoke too soon.  As you should just have been told, there was at\n' ...
           'least one error when I tried to read from your daq device a second time.  Odd that\n' ...
           'the device passed such a test once and then failed...  but that''s how things look\n' ...
           'to me.\n']);
  return;
end

if ~all(TheWrittenData(2:end) == MemWriteTestData)  
  fprintf(['\nUh oh...  I spoke too soon.  The data that I just read from the EEPROM of your\n' ...
           'daq device does not match the data that I think I just wrote to it.  I do not know\n' ...
           'why that might be.  Did you unplug it (sorry for such a lame question...).\n\n']);
  return;
end

fprintf('\nI just read what I wrote, and it looks like I wrote what I thought I wrote!');

err=DaqMemWrite(daq(1),512,TheOriginalData(2:end));
if err.n
  fprintf(['\nHmmmm...  I just tried to write your original data back to the EEPROM of your daq\n' ...
           'device.  That operation apparently failed.  I hope that I did not do any serious\n' ...
           'damage here...  It is unlikely that I did, but it is also unlikely that this function\n' ...
           'would fail here when it worked before.  Sorry things didn''t go more smoothly.  This\n' ...
           'is all I can tell you about the problem:\n\n']);
  err
  fprintf(['If you want to take matters into your own hands, the data I originally read from your\n' ...
           'daq''s EEPROM was:\n\n']);
  TheOriginalData(2:end)
  return;
end

fprintf(['\nEEPROM of your daq device has been restored to what it was before this test began.\n' ...
         'So far so good!\n\nMoving on to test mode changes...']);
       
TheStatus = DaqGetStatus(daq);
if isempty(TheStatus)
  fprintf(['\nFailed to receive status report...  Look inside DaqGetStatus and run\n' ...
           'individual commands to try to figure out why this did not work.  In the\n' ...
           'mean time, I will take my leave of you.\n\n']);
  return;
else
  if isfield(TheStatus,'master')
    DaqSetSync(daq,TheStatus.master);
    NewStatus = DaqGetStatus(daq);
    if xor(TheStatus.master,NewStatus.master)
      DaqSetSync(daq,~TheStatus.master);
    else
      fprintf(['\nIt looks like I had trouble flipping the master sync status bit\n' ...
               'I don''t want to mess things up, so I return control to you.\n\n']);
      return;
    end
    FinalStatus = DaqGetStatus;
    if FinalStatus.master ~= TheStatus.master
      fprintf(['\nIt looks like I had trouble re-setting the master sync status bit\n' ...
               'after I changed it.  I am going to stop now.  I hope I haven''t caused a problem.\n\n']);
      return;
    else
      fprintf('\nSuccessfully toggled sync status bit.  Moving on...');
    end
  else
    fprintf('\nThere was a status returned, but it was missing the "master" field.  I will bail.\n\n');
    return;
  end % if isfield(TheStatus,'master'); else
  if isfield(TheStatus,'rising')
    DaqSetTrigger(daq,~TheStatus.rising);
    NewStatus = DaqGetStatus(daq);
    if xor(TheStatus.rising,NewStatus.rising)
      DaqSetTrigger(daq,TheStatus.rising);
    else
      fprintf(['\nIt looks like I had trouble flipping the trigger rising status bit\n' ...
               'I don''t want to mess things up, so I return control to you.\n\n']);
      return;
    end
    FinalStatus = DaqGetStatus;
    if FinalStatus.rising ~= TheStatus.rising
      fprintf(['\nIt looks like I had trouble re-setting the trigger rising status bit\n' ...
               'after I changed it.  I am going to stop now.  I hope I haven''t caused a problem.\n\n']);
      return;
    else
      fprintf('\nSuccessfully toggled trigger status bit.  Moving on...');
    end
  else
    fprintf('\nThere was a status returned, but it was missing the "rising" field.  I will bail.\n\n');
    return;
  end % if isfield(TheStatus,'rising'); else
  if isfield(TheStatus,'program')
    DaqPrepareDownload(daq,~TheStatus.program);
    NewStatus = DaqGetStatus(daq);
    if xor(TheStatus.program,NewStatus.program)
      DaqPrepareDownload(daq,TheStatus.program);
    else
      fprintf(['\nIt looks like I had trouble flipping the update program mode bit\n' ...
               'I don''t want to mess things up, so I return control to you.\n\n']);
      return;
    end
    FinalStatus = DaqGetStatus;
    if isempty(FinalStatus)
      fprintf(['\nIt looks like I had trouble reading the updated status from the device\n' ...
               'I don''t want to mess things up, so I return control to you.\n\n']);
      return;
    end
    if FinalStatus.program ~= TheStatus.program
      fprintf(['\nIt looks like I had trouble re-setting the update program mode bit\n' ...
               'after I changed it.  I am going to stop now.  I hope I haven''t caused a problem.\n\n']);
      return;
    else
      fprintf('\nSuccessfully toggled program status bit.  Moving on...\n');
    end
  else
    fprintf('\nThere was a status returned, but it was missing the "program" field.  I will bail.\n\n');
    return;
  end % if isfield(TheStatus,'program'); else
  
end

fprintf('\n');

fprintf('\nThe following tests assess all the %s commands, reporting any errors.\n',devices(daq(1)).product);
fprintf('\n** DIGITAL COMMANDS \n** DaqDConfigPort, DaqDIn, ');

if Is1608
  fprintf('and DaqDOut.\n\nDaqDConfigPort: configuring digital port for output.\n');
  err=DaqDConfigPort(daq,0);
  if err.n
    fprintf('Attempt to configure digital port failed.  This is all I can tell you about that:\n\n');
    err
  end
else
  % DaqDConfigPort
  fprintf('DaqDOut, and DaqGetAll.\n\nDaqDConfigPort: configuring digital ports for output.\n');
  err=DaqDConfigPort(daq(1),0,0); % configuring digital port A for output
  err=DaqDConfigPort(daq(1),1,0); % configuring digital port B for output
end

% I never had the following problem, so I don't know how helpful this is... --
% mpr

% Make sure the USB-1208FS is "attached".
if streq(err.name,'kIOReturnNotAttached')
    fprintf(['\nkIOReturnNotAttached: Mac OS error message says %s is "not attached".\n'...
        'But we know it is. We suggest that you quit and restart MATLAB. In our experience\n'...
        'that always clears up the problem.\n'],devices(daq(1)).product);
    error(sprintf('%s not attached.',devices(daq(1)).product));
end

% DaqDOut
if Is1608
  fprintf(['\nDaqDOut: random test patterns on DIO port. This is a basic functionality\n'...
      'test, showing that we can indeed read back what we wrote.\n']);
  a=Randi(255);
  err=DaqDOut(daq,a);
  fprintf('DaqDOut: %3d.\n',a);  
else % if Is1608 (DaqDOut test)
  fprintf(['\nDaqDOut: random test patterns on ports A and B. This is a basic functionality\n'...
      'test, showing that we can indeed read back what we wrote.\n']);
  a=Randi(255);
  err=DaqDOut(daq(1),0,a);
  b=Randi(255);
  err=DaqDOut(daq(1),1,b);
  fprintf('DaqDOut: %3d %3d.\n',a,b);
end % if Is1608; else (DaqDOut test)

if debugging
    TestClearMex(daq);
end

% DaqDIn
if Is1608
  fprintf('\nDaqDIn: reading digital port.\n');
  data=DaqDIn(daq);
  if isempty(data)
    disp('No data received.  That seems pathological so I will stop and let you investigate the problem.');
    return;
  else
    fprintf('DaqDIn: %3d.\n',data);
    if data ~= a
      fprintf(['What I read and what I wrote are not the same.  I will stop and let you see if\nyou can figure out why.\n' ...
               'My first guess is that you have grounded one or more of the DIO pins.  Even with the port configured\n' ...
               'for output, that seems to screw things up.  Disconnect all wires from the DIO terminals and try running\n' ...
               'DaqTest again.\n\n']);
      return;
    else
      disp('Data read matches data written.  Excellent!');
    end
  end
else % if Is1608 (DaqDIn test)
  fprintf('\nDaqDIn: reading digital ports.\n');
  data=DaqDIn(daq(1));
  if ~isempty(data)
    fprintf('DaqDIn: %3d %3d.\n',data);
    if length(data) ~= 2 | ~all(data == [a b])
      disp('Mismatch between what I read and what I wrote.  I will stop to let you investigate.');
      return;
    else
      disp('Data read matches what was written.  Excellent!');
    end
  else
    disp('No data received.  That seems pathological so I will stop and let you investigate the problem.');
    return;
  end
end % if Is1608; else (DaqDIn test)

% Bit functions
if Is1608
  fprintf('\nAbout to test ability to configure, read, and write individual bits...');
  
  fprintf('\nTwo''s complement of randomly chosen value: %d\n',bitcmp(a,8));
  TheBitValues = zeros(1,8);
  for k=1:8
    TheBitValues(k) = bitget(bitcmp(a,8),k);
  end
  DaqDWriteBit(daq,0:7,TheBitValues);
  TheResults = DaqDReadBit(daq,0:7);
  if ~all(TheResults == TheBitValues)
    disp('When I tried to write and read individual bits I came up with a different answer.  Stopping for you to investigate.');
    return;
  end
  TheWrittenValue = DaqDIn(daq);
  if TheWrittenValue == bitcmp(a,8)
    fprintf(['\nYes, the value I read back is the same as the bit complement of the previously written value!\n\n' ...
             'This test was not terribly stringent, and none of the DIO tests really check to see that your\n' ...
             'device accurately reads the inputs.  If you want to test that, you can do this:\n\n' ...
             '     DaqDConfigPort(device,1);\n\n' ...
             'and then try various combinations of wiring.  To check the value being read by all terminals at once,\n' ...
             'use:\n\n' ...
             '     DaqDReadBit(device,0:7)\n\n' ...
             '(no semi-colon at the end because you want to see the output).  Any of the channels connected to\n' ...
             'ground should read 0; others should read 1.  So, for instance, if you wire pin 21 to pin 22, pin 25\n' ...
             'to pin 26, and pin 33 to pin 34, and ran the DaqReadBit command, you should get:\n\n' ...
             '          0     1     0     1     1     1     0     1\n\n' ...
             'as an answer.  Equivalently, DaqDIn should return 186 in that case.  It is also possible to configure\n' ...
             'individual bits independently.  When I tried it I got behavior I did not fully expect (for instance,\n' ...
             'configuring a bit as output doesn''t always set the value of that bit when you write to it... as if\n' ...
             'the state of the bit when read is taken from an actual reading even though it shouldn''t be.  I did not\n' ...
             'test this too carefully, but I have no current reason to believe that there are any software errors in\n' ...
             'DaqDConfigPortBit.\n\n']);
  else
    fprintf(['Uh-oh, when I tried to read the whole port again as a single 8-bit value, I got\n' ...
             'a different answer.  Stopping for you to figure out why.\n\n']);
    return;
  end
else % if is1608 (Bit functions test)
  disp('Bitwise DIO functions have not been written for -1208 and/or -1408 daqs.  If these functions');
  disp('are important to you, you should edit them (DaqDConfigPortBit, DaqDWriteBit, DaqDReadBit) and');
  disp('then edit DaqTest so that the functions are tested on your hardware.');
  fprintf('\n\n');
end % if is1608; else (Bit functions test)

if debugging
    TestClearMex(daq);
end

% DaqGetAll
if Is1608
  fprintf('\nA working version of DaqGetAll has not been produced for the 1608, so skipping this test.\n');
else
  fprintf('\nDaqGetAll: reading all analog and digital inputs.\n');
  data=DaqGetAll(daq(1));
  if isempty(data)
    fprintf('Nothing received.\n');
  % I put this here before I set program to skip this test for 1608; if you fix
  % DaqGetAll, you will still need something like this as the 1608 has only the
  % one digital port compared to the 1208's two ports.  -- mpr
  elseif Is1608
    fprintf('data.digital: %3d.\n',data.digital);
  else
    fprintf('data.digital: %3d %3d.\n',data.digital);
  end
end
if debugging
    TestClearMex(daq);
end

% DIn/DOut speed test

fprintf(['\nDaqDOut & DaqDIn: write & read back one hundred random values as fast as\n' ...
         'possible. This test assesses reliability and latency, the time for data to \n' ...
         'go from host to device and back.\n']);
       
wrong=0;
missing=0;
if Is1608
  t=GetSecs;
  for trials=1:100
    % DaqDOut
    a=Randi(255);
    err=DaqDOut(daq,a);
    
    % Tried the following command instead of the previous command to see if 
    % the device is excessively slowed by the additional wrapping material in 
    % DaqDOut necessitated by not knowing in advance what type of Daq the user
    % has.  Found that it made *NO* difference! -- mpr
    %
    % PsychHID('SetReport',daq,2,4,uint8([0 a]));
    
    % DaqDIn
    data=DaqDIn(daq,1);
    if ~isempty(data)
      if a~=data
        wrong=wrong+1;
      end
    else
      missing=missing+1;
    end
    if err.n
      break;
    end
  end
  t=GetSecs-t;
else
  t=GetSecs;
  for trials=1:100
    % DaqDOut
    a=Randi(255);
    err=DaqDOut(daq(1),0,a);
    % DaqDIn
    data=DaqDIn(daq(1),2);
    if ~isempty(data)
      if a~=data(1)
        wrong=wrong+1;
      end
    else
      missing=missing+1;
    end
    if err.n
      break;
    end
  end
  t=GetSecs-t;
end

if missing==trials
    fprintf('Nothing received.\n');
else
    fprintf('Achieved %.0f Hz, i.e. %.0f ms cycle time. %.0f errors and %.0f missing in %.0f trials.\n',...
        trials/t,1000*t/trials,wrong,missing,trials);
end
if debugging
    TestClearMex(daq);
end

% DaqDOut
if Is1608
  fprintf('\nDaqDOut: producing fast squarewave digital output.\n');
  DaqDConfigPort(daq,0); % output
  for i=1:500
    err=DaqDOut(daq,255);
    err=DaqDOut(daq,0);
    if err.n
      break;
    end
  end
else
  fprintf('\nDaqDOut: producing fast squarewave digital output on port A.\n');
  DaqDConfigPort(daq(1),0,0); % output
  for i=1:500
    err=DaqDOut(daq(1),0,255);
    err=DaqDOut(daq(1),0,0);
    if err.n
      break;
    end
  end
end % if Is1608; else (DaqDOut test II)

if debugging
    TestClearMex(daq);
end

if Is1608
  CalibrateNow=TwoStateQuery('If you would like to calibrate analog channel 0 (recommended), wire pin 1 to pin 17 now. ',{'Okay','Skip'});
  if CalibrateNow > 0
    DaqCalibrateAIn(daq,0);
  end
  DoSquareTest = TwoStateQuery('Is pin 1 wired to pin 21?');
  if DoSquareTest > 0
    
    fprintf(['\n\nPutting square wave output through Digital Port bit 0 and reading it through\n' ...
             'Analog Input Channel 0...\n']);
           
    options.lowChannel = 0;
    options.highChannel = 0;
    options.range = 1;
    options.count = Inf;
    options.f = 100;
    
    DaqDConfigPort(daq,0);
    DaqDOut(daq,0);
    TheState=0;
    
    TheParams=DaqAInScanBegin(daq,options);

    TheInitialStart = GetSecs;
    WaitSecs(0.125);

    TheStart = GetSecs;

    for k=1:11
      AlreadyFlipped=0;
      while GetSecs-TheStart < k/4
        if ~AlreadyFlipped
          TheState = rem(TheState+1,2);
          DaqDOut(daq,TheState);
          AlreadyFlipped = 1;
        end
      end
    end
    
    WaitSecs(0.1);
    [TheData,TheParams] = DaqAInScanEnd(daq,options);

    TotalTimeElapsed = GetSecs-TheInitialStart;

    fprintf('Time elapsed: %f seconds\n',TotalTimeElapsed);
    fprintf('Number of data points: %d\n',length(TheData));
    fprintf('Expected number of data points: %d\n\n',floor(TheParams.fActual*TotalTimeElapsed));

    figure('Tag','DaqTestFig'); 
    plot((0:(size(TheData,1)-1))/TheParams.fActual-TheStart+TheInitialStart,TheData,'LineWidth',3);
    xlabel('Time (Seconds)');
    ylabel('Potential (Volts) ');
    title(sprintf('This should be a 5 V square wave with\na frequency of 2 Hz sampled at 100 Hz'));
    grid on;
    drawnow;
  end    
else % Is1608 (DaqAOut tests)
  fprintf('\n** ANALOG COMMANDS \n** DaqAIn, DaqAOut, DaqAInScan, DaqAOutScan, DaqALoadQueue\n');

  % DaqAOut: 1 kHz squarewave
  outTick=0.0005; % s
  duration=0.5; % s
  fprintf('\nDaqAOut: producing %.0f kHz squarewave output voltage for %.1f s.\n',0.5/outTick/1000,duration);
  tuntil=GetSecs;
  for i=1:duration/outTick
    tuntil=tuntil+outTick;
    WaitSecs(tuntil-GetSecs);
    err=DaqAOut(daq(1),0,mod(i,2)); % D/A 0
    err=DaqAOut(daq(1),1,mod(i,2)); % D/A 1
    if err.n
      break;
    end
  end

  % DaqAOut & DaqAIn: 4 Hz sinewave
  f=4;
  fprintf([
      '\nDaqAOut & DaqAIn: producing %.0f Hz sinewave and triangle wave output voltages,\n'...
      'on two channels, and reading them back in through the analog inputs. We plot \n'...
      'the readings in Figure 1. (It''s just noise unless you''ve installed wires\n'...
      'connecting output to input.)\n'],f);
  start=GetSecs;
  time=0:0.01:0.5;
  x=f*2*pi*time;
  sineWave=0.5+0.5*sin(x);       % Raised sine. Positive.
  triangleWave=0.5+0.5*trin(x);  % Raised triangle. Positive.
  v0=[];
  v1=[];
  for i=1:length(time)
    WaitSecs(time(i)+start-GetSecs);
    err=DaqAOut(daq(1),0,sineWave(i));
    err=DaqAOut(daq(1),1,triangleWave(i));
    if err.n
      break;
    end
    v0(i)=DaqAIn(daq(1),0,3);
    v1(i)=DaqAIn(daq(1),1,3);
  end
  if ~isempty(v0)
    figure(1);
    plot(time,v0,'r',time,v1,'g');
    ylabel('Volts');
    xlabel('Time (s)');
    title('Two channels (sine and triangle waves) put out by DaqAOut and read back in by DaqAIn.');
    text(0.15,1.9,'This graph will be meaningless noise unless you previously');
    text(0.15,1.8,'connected output to input. This test requires 4 wires ');
    text(0.15,1.7,'connecting analog output to input. Connect pin 1 to 13, ');
    text(0.15,1.6,'2 to 12, 4 to 14, and 5 to 12.');
    figure(1);
  else
    fprintf('Nothing received.\n');
  end
  if debugging
  % fprintf('TestClearMex once crashed at line 269.\n');
    TestClearMex(daq);
  end

  % DaqAInScan
  fprintf('\nDaqAInScan: sampling analog input.\n');
  options.lowChannel=[];
  options.highChannel=[];
  options.count=1000;
  options.f=2000;
  options.immediate=0;
  options.trigger=0;
  options.print=0;
  options.channel=0:0;
  options.range=3*ones(size(options.channel));
  c=length(options.channel);
  % n is sample/channel/report
  if options.immediate
    n=1;
  else
    n=31/c;
  end
  start=GetSecs;
  [data,params]=DaqAInScan(daq(1),options);
  stop=GetSecs;
  fprintf('Got %d (of %d) sample/channel on %d channels at %.0f Hz.\n',...
      size(data,1),options.count,size(data,2),params.fActual);
  if length(params.times)>1
    t=params.times;
    fprintf('Received %.1f report/s, %.1f sample/channel/s.\n',...
        (length(t)-1)/(t(end)-t(1)),(size(data,1)-n)/(t(end)-t(1)));
  end
  if debugging
  % fprintf('TestClearMex once crashed at line 302.\n');
    TestClearMex(daq);
  end

  % DaqAInScanBegin, DaqAInScanContinue, DaqAInScanEnd
  % Works well for f up to 2048/c sample/channel/s, where c is number of
  % channels. Currently (18 April 2005) unreliable at higher rates.
  c=length(options.channel);
  for log2f=11
    options.f=2^log2f/c;
    fprintf('\nDaqAInScanBegin, DaqAInScanContinue, DaqAInScanEnd: sampling analog input. \n');
    duration=1;
    options.count=duration*options.f;
    options.immediate=0;
    params=DaqAInScanBegin(daq(1),options);
    params=DaqAInScanContinue(daq(1),options);
    params=DaqAInScanContinue(daq(1),options);
    [data,params]=DaqAInScanEnd(daq(1),options);
    fprintf('Got %d (of %d) sample/channel on %d channels at %.0f Hz.\n',size(data,1),options.count,size(data,2),params.fActual);
    if length(params.times)>1
      t=params.times;
      c=size(data,2);
      % n is sample/channel/report
      if options.immediate
        n=1;
      else
        n=31/c;
      end
      fprintf('Received %.1f report/s, %.1f sample/channel/s.\n',(length(t)-1)/(t(end)-t(1)),(size(data,1)-n)/(t(end)-t(1)));
    end
  end
  if debugging
  %	fprintf('TestClearMex once crashed at line 390.\n');
    TestClearMex(daq);
  end

  % DaqAOut & DaqAInScan: 4 Hz sinewave
  % This runs well at slow sampling rates (100 Hz). Attempting to run at high
  % rates (e.g. 1000 Hz) results in losing most of the data. This isn't a
  % bug. It's asking the USB-1208FS to do two things at once (AOut and
  % AInScan) and clearly they interfere with each other. None of the
  % Measurement Computing literature that I've read mentions the issue of
  % doing two things at once, so there's no promise to live up to. This
  % simultaneous in and out is an excellent way to test the capabilities of
  % the USB-1208FS without any extra equipment, but is probably not a useful
  % model for experimental work since it limits you to low sampling rates. If
  % you need to sample in and out at the same time you may want to buy two
  % USB-1208FS units and use one for input and the other for output.
  f=1;
  fprintf([
      '\nDaqAOut & DaqAInScan: producing %.0f Hz sinewave and square wave output\n'...
      'voltages, on two channels, and reading them back in through the analog inputs. \n'...
      'We plot the readings in Figure 2. (It''s just noise unless you''ve installed\n'...
      'wires connecting output to input.)\n'],f);
  time=0:0.02:5;
  x=f*2*pi*time;
  sineWave=0.5+0.5*sin(x);       % Raised sine. Positive.
  triangleWave=0.5+0.5*trin(x);  % Raised triangle. Positive.
  squareWave=round(sineWave);
  % In
  v0=[];
  v1=[];
  options.f=100;
  options.channel=[];
  options.range=[];
  options.lowChannel=0;
  options.highChannel=0;
  options.count=round(max(time)*options.f);
  options.immediate=0;
  channel=options.lowChannel:options.highChannel;
  range=3*ones(size(channel));
  for i=channel
    DaqAIn(daq(1),i,3);% set gain range
  end
  start=GetSecs;
  params=DaqAInScanBegin(daq(1),options);
  for i=1:length(time)
    WaitSecs(time(i)+start-GetSecs);
    err=DaqAOut(daq(1),0,sineWave(i));
    err=DaqAOut(daq(1),1,squareWave(i));
    if err.n
      break;
    end
    tOut(i)=GetSecs-start;
  end
  params=DaqAInScanContinue(daq(1),options);
  [data,params]=DaqAInScanEnd(daq(1),options);
  fprintf('Got %.0f (of %.0f) sample/channel on %d channels at %.0f Hz.\n',...
    size(data,1),options.count,size(data,2),params.fActual);
  if ~isempty(data)
    t=(1:size(data,1))/params.fActual;
    v0=data(:,1);
    figure(2);
    plot(t,v0,'r');
    if size(data,2)>=2
      v1=data(:,2);
      hold on
      plot(t,v1,'g');
      hold off
      title(sprintf('%.0f Hz sine & square waves put out by DaqAOut and read back in by DaqAInScan.',f));
    else
      title(sprintf('%.0f Hz sine wave put out by DaqAOut and read back in by DaqAInScan.',f));
    end
    ylabel('Volts');
    xlabel('Time (s)');
  end
  if debugging
    TestClearMex(daq);
  end

  % DaqAOutScan. Analog output scan.
  % Works well for f up to 1024 sample/channel/s on one channel, and 256
  % sample/channel/s on two channels. Currently (28 April 2005) unreliable at
  % higher rates.
  for log2f=10
    options.f=2^log2f; % sampling frequency in Hz
    duration=0.999; % s
    fSine=10; % Hz
    options.lowChannel=0;
    options.print=0;
    outTick=1/options.f; % s
    wave=0.5+0.5*sin(fSine*2*pi*(0:outTick:duration)); % Raised sine. Positive.
    if 1
      % works for f up to 1024
      options.highChannel=0;
    else
      % works for f up to 256
      options.highChannel=1;
      wave=[wave' wave'];
    end
    options.getReports=1;
    c=1+options.highChannel-options.lowChannel;
    fprintf('\nDaqAOutScan: producing %.0f Hz sine for %.0f s sampled at %.0f Hz on %d channels.\n',...
      fSine,duration,options.f,c);
    params=DaqAOutScan(daq(1),wave,options);
    if isempty(params.start)
      params.start=nan;
    end
    if isempty(params.end)
      params.end=nan;
    end
    fprintf('Sent %.0f (out of %.0f) samples/channel on %d channels in %.0f (out of %.0f) ms.\n',...
      params.countActual,length(wave),c,1000*(params.end-params.start),1000*length(wave)/options.f);
    r=(params.numberOfReportsSent-1)/(params.end-params.start);
    fprintf('Sending speed was %.0f report/s, %.0f sample/channel/s.\n',r,r*32/c);
  end
  if debugging
  %	fprintf('TestClearMex once crashed at line 499.\n');
    TestClearMex(daq);
  end

  % DaqALoadQueue.
  fprintf('\nDaqALoadQueue: setting channel 0 to gain range 0.\n');
  err=DaqALoadQueue(daq(1),0,0);
  if debugging
    TestClearMex(daq);
  end
end % Is1608; else (DaqAOut tests)

waitsecs(0.2);

fprintf('\n** COUNTER COMMANDS \n** DaqCIn, DaqCInit\n');

% DaqCIn. Reading counter
fprintf('\nDaqCIn: reading the counter.\n');
count=DaqCIn(daq(1));
if ~isempty(count)
    fprintf('Count is %d.\n',count);
else
    fprintf('Nothing received.\n');
end

if Is1608
  IShouldTestCounter = TwoStateQuery('If you would like to test the counter, make sure pin 21 is connected to pin 38.  Then click "Yes".');
  if IShouldTestCounter > 0
    DaqCInit(daq);
    StartCount = DaqCIn(daq);
    if StartCount
      error('Counter did not reset to zero.  Sorry!');
    end
    DaqDConfigPortBit(daq,0,0);
    for k=1:150
      DaqDWriteBit(daq,0,1);
      DaqDWriteBit(daq,0,0);
    end
    EndCount = DaqCIn(daq);
    if EndCount ~= 150
      fprintf(sprintf('Counter reads %d when it should read 150!  Oops!',EndCount));
      if abs(EndCount-150) > 1
        error('In my tests, some times one count was missed, so I''ll accept that, but...');
      else
        fprintf(['\nUsually my counts were exact, but some times I missed one, particularly if I ran\n' ...
                 'the square wave test.  We''ll call this a pass, but just barely.  Moving on...\n\n']);
      end
    else
      fprintf('\nOne hundred and fifty pulses sent to the counter, 150 pulses counted.  Moving on...\n\n');
    end
  end
end % if Is1608
    

if debugging
    TestClearMex(daq);
end

% DaqCInit. Resetting counter to zero.
fprintf('\nDaqCInit: resetting counter to zero.\n');
err=DaqCInit(daq(1));

% I wrote my own versions of these above before I got down here and realized
% Denis wrote tests of these functions too...  I "if 0"d most of the code below, 
% but in the indicated places, it was like that when I got here -- mpr
%
% fprintf(['\n** MISCELLANEOUS COMMANDS \n** DaqGetStatus, DaqSetCal, DaqSetSync, DaqSetTrigger\n']);


% Denis had this test here (and had DaqBlinkLED listed in the fprintf that
% immediately precedes this), but it made more sense to me to test this up
% top and use DaqBlinkLED as a way for users to choose which device to test
% if they have more than one. I recommend using my code for this function since 
% I do more with it in my tests.  -- mpr
if 0
  % DaqBlinkLED
  fprintf('\nDaqBlinkLED: blinking the LED.\n');
  err=DaqBlinkLED(daq(1));
end

if 0 % This was commented out before I got here -- mpr
    % DaqReset. Optional reset. Make sure the USB-1208FS is "attached". In
    % theory it's nice to detect anomalous behavior and fix it, by
    % resetting the device. However, this requires a call to CLEAR PsychHID to
    % re-enumerate, which may result in a crash when you next ask PsychHID to 
    % receive reports. Don't use DaqReset. Quitting and restarting MATLAB is a 
    % reliable way of reestablishing normal communication with the USB-1208FS.
    err=PsychHID('SetReport',daq(1),2,64,uint8(64)); % Blink LED
    if streq(err.name,'kIOReturnNotAttached')
        fprintf('\nMac OS error message says %s is "not attached". But we know it is.\n',devices(daq(1)).product);
        fprintf('We will attempt to reestablish communication by re-enumerating, resetting the USB, and re-enumerating again. ');
        err=DaqReset(daq(1));
        fprintf('End of reset. Hopefully your %s is working again.\n',devices(daq(1)).product);
    end
end

if 0
  for i=[1 0]
      % DaqSetSync
      fprintf('\nDaqSetSync: configure synchronization to %d. (0 for master, 1 or 2 for slave)\n',i);
      err=DaqSetSync(daq(1),i);

      % DaqGetStatus
      fprintf('\nDaqGetStatus: reading the status bits.\n');
      status=DaqGetStatus(daq(1));
      if ~isempty(status)
          if status.master
              fprintf('master.\n');
          else
              fprintf('slave.\n');
          end
      else
          fprintf('Nothing received.\n');
      end
  end
  if debugging
      TestClearMex(daq);
  end

  if Is1608
    fprintf(['\nYou can test the calibration if you want; but I didn''t see a point\n' ...
             'to the test that was run before.  It set the calibration voltage for one\n' ...
             'second, but didn''t even tell you the pins until it was testing them.  Note\n' ...
             'the pins are different (CAL pin is pin 17 (with pin 16 being the nearest\n' ...
             'ground) in the 1608FS.  If you want to monitor the voltage across these\n' ...
             'pins, go ahead and run the test at "DaqSetCal".  I think the function\n' ...
             'should work as is, but I have not tested it.  -- mpr \n\n']);
  else
    % DaqSetCal
    fprintf(['\nDaqSetCal: setting calibration voltage output to +2.5 V for 1 s. \n'...
        'CAL is pin 16; pin 15 is ground.\n']);
    err=DaqSetCal(daq(1),1); % SetCal +2.5 V
    WaitSecs(1);
    err=DaqSetCal(daq(1),0); % SetCal 0 V

    % DaqSetTrigger
    fprintf('\nDaqSetTrigger: setting to trigger on falling edge.\n');
    err=DaqSetTrigger(daq(1),0);
  end % if Is1608; else
end % if 0
  
% Denis originally tested DaqMemRead here, but I moved the test up front because
% it does not depend upon the wiring of the terminals.  Hence it is a more
% stringent test; if it fails, it seems to me there is no reason to test
% anything else.  This is another test I recommend you stick with my code 
% instead of reverting.-- mpr
if 0
  fprintf(['\n** MEMORY COMMANDS\n'...
      '** DaqMemRead, DaqMemWrite, DaqReadCode, DaqPrepareDownload, DaqWriteCode,\n'...
      '** DaqWriteSerialNumber\n']);
  fprintf(['\nWe only test the two read commands, since the write commands could\n'...
      'potentially screw up the firmware, and we have no immediate need for\n'...
      'writing to memory.\n']);
  if debugging
      TestClearMex(daq);
  end

  % DaqMemRead
  fprintf('\nDaqMemRead: Reading memory.\n');
  data=DaqMemRead(daq(1),hex2dec('100'),62);
  if isempty(data)
      fprintf('Nothing received.\n');
  end
end

% This is another test that seems pretty pointless to me.  It might work as is,
% but if you don't put code in, how can you know what should be there?  The fact
% that *something* is received is not a terribly stringent test.  My guess is
% that if anyone wants to use this function, they'll devise their own tests of
% it, and the tests will be a good deal more meaningful than this.  I don't feel
% a need to use the function at the moment, so I'm bailing on writing that code.
%  -- mpr
if 0
  % DaqReadCode
  fprintf('\nDaqReadCode: Reading program memory.\n');
  data=DaqReadCode(daq(1),0,62);
  if isempty(data)
      fprintf('Nothing received.\n');
  end
  if debugging
      TestClearMex(daq);
  end
end

% The following was in Denis's original version; his comment is now incorrect
% because this function is tested above.  I leave this here for posterity in
% case anyone wants to revert to Denis's version. -- mpr
if 0
    % NOT TESTED. I don't need these functions, which write to memory, and
    % I don't want to risk screwing up my USB-1208FS firmware. If you decide to
    % try this, pick your addresses carefully, after consulting the table
    % of memory types: "help daqwritecode".

    % DaqMemWrite
    fprintf('\nDaqMemWrite: Writing memory.\n');
    err=DaqMemWrite(daq(1),0,1:2);

    % DaqPrepareDownload
    fprintf('\nDaqPrepareDownload: Preparing for program memory download.\n');
    err=DaqPrepareDownload(daq(1));

    % DaqWriteCode
    fprintf('\nDaqWriteCode: Writing program memory.\n');
    err=DaqWriteCode(daq(1),0,1:2);
end

% My history here was a bit odd... My recollection is that the first time I ran
% PsychHID('Devices'), the serial number reported for my USB-1608FS was 0.  I
% ran DaqWriteSerialNumber and tried to get the value set correctly.  I wasn't
% sure it worked, but later I found that the value was set (except that the
% documentation for my device has a 9-character serial number and the number is
% truncated to eight characters.  Nevertheless, I am with Denis that it is
% probably unwise to rewrite your serial number unless you absolutely know you
% need to.  So I leave this functionally commented out. -- mpr
if 0
    % WARNING: you probably do NOT want to run this command, because it
    % will over-write your factory-assigned serial number. I tested this
    % on my USB-1208FS and it works fine. Note that the new serial number
    % won't show up until you unplug and reconnect your device.

    % DaqWriteSerialNumber
    serialString='00000123';
    err=DaqWriteSerialNumber(daq(1),serialString);
    fprintf('\nDaqWriteSerial: setting the serial number to "%s".\n',serialString);
end

if Is1608
end


fprintf('\nDone.\n');

function y=trin(x)
% y=trin(x)
% Triangle wave. Has same peaks as SIN, but is linear between those peaks.
y=4*mod(x/2/pi,1);
fy=floor(y);
i=find(fy==1 | fy==2);
y(i)=2-y(i);
i=find(fy==3);
y(i)=y(i)-4;
return

function TestClearMex(daq)
% TestClearMex is being used by dgp to track down a crash of PsychHID associated
% with CLEAR MEX. 
options.printCrashers=1;
% PsychHID('ReceiveReports',daq(1),options);
% 
% % DaqDIn
% fprintf('\nDaqDIn: reading digital ports.\n');
% data=DaqDIn(daq(1));
% if ~isempty(data)
%     fprintf('DaqDIn: %3d %3d.\n',data);
% else
%     fprintf('DaqDIn: Nothing received.\n');
% end

fprintf('CLEAR MEX\n');
clear mex;

PsychHID('ReceiveReports',daq(1),options);

% DaqDIn
fprintf('DaqDIn: reading digital ports.\n');
data=DaqDIn(daq(1));
if ~isempty(data)
    fprintf('DaqDIn: %3d %3d.\n',data);
else
    fprintf('DaqDIn: Nothing received.\n');
end
return