home *** CD-ROM | disk | FTP | other *** search
/ 64'er / 64ER_CD.iso / utilatar / siocopy / siocopy.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1994-07-13  |  22.7 KB  |  706 lines

  1. #include <stdio.h>
  2. #include <dos.h>
  3. #include <timer.h>
  4. #include <conio.h>
  5. #include <stdlib.h>
  6.  
  7. #define N 1000
  8.  
  9.  
  10. //************************************************************************
  11. //**   Cable specifications:                        **
  12. //**                                    **
  13. //**   Pinouts:                                **
  14. //**           IBM Parallel Port      Atari SIO    name        **
  15. //**                                    **
  16. //**             1    ----------------->  7           command/        **
  17. //**             14    <----------------   5           dataout        **
  18. //**             16    ----------------->  10           vcc/rdy        **
  19. //**             17    ----------------->  3           datain        **
  20. //**             24    -----------------   4           gnd        **
  21. //**             25    -----------------   6           gnd        **
  22. //**                                    **
  23. //**                                    **
  24. //**  Connector Specs:                            **
  25. //**        IBM Parallel Port        DB25M     25 pin male d-shell    **
  26. //**   (view as if you were plugging the connector into your face)     **
  27. //**         1   2  3  4  5  6  7  8  9  10 11 12 13        **
  28. //**           14 15 16 17 18 19 20 21 22 23 24 25            **
  29. //**                                    **
  30. //**                                    **
  31. //**                                    **
  32. //**        Atari SIO            Molex     13 pin            **
  33. //**   (view as if you were plugging the connector into your face)     **
  34. //**                                    **
  35. //**           1  3  5  7  9  11  13                **
  36. //**             2    4  6  8     10  12                    **
  37. //**                                    **
  38. //**                                    **
  39. //**    Notes:                                **
  40. //**      (1) Keep the wire length less than 3 feet.            **
  41. //**                                    **
  42. //************************************************************************
  43.  
  44.  
  45. //*****************This is the structure of the xf551 configuration record.
  46. //This is here for information only, the struct is not used in this program.
  47. struct DRVCONFIG
  48. {
  49. char    DRVTRC;        // number of tracks (0x28)
  50. int    DRVSTP;        // drive step rate (0)
  51. char    DRVSEC;        // number of sectors on a track (0x12, 0x1a)
  52. char    DRVSID;        // number of disk sides (0=single 1=double)
  53. char    DRVDEN;        // drive density 0 = sd, 4 = dd
  54. int     DRVBYT;        // bytes per sector 0x80 = 128, 0x100 = 256
  55. char     DRVSEL;        // drive address (d1: = 1)
  56. char    DRVSER;        // drive serial rate (0x41 = 19200bps)
  57. int    DRVMSC;        // ???
  58. char    CHKSUM;        // checksum for above data
  59. };
  60.  
  61. //********Below are the configuration records for the various drive types
  62. //single sided single density
  63. char d810[13] = {0x28,00,00,0x12,0x00,0x00,0x00,80,0x01,0x41,00,00,0xfc};
  64. //single sided enhanced density
  65. char d1050[13] ={0x28,00,00,0x1a,0x00,0x04,0x00,80,0x01,0x41,00,00,0x09};
  66. //single sided double density
  67. char xf551[13] ={0x28,00,00,0x12,0x00,0x04,0x01,00,0x01,0x41,00,00,0x82};
  68.  
  69. char data[512];
  70. unsigned data_valid, data_xmit;
  71.  
  72. //************************************************************************
  73. //**    calibration(freq)                        **
  74. //**        This routine estimates the number of loop counts    **
  75. //**        in 25uS.   This count is used to synchronize this    **
  76. //**        program with the sio data rate expected by the         **
  77. //**            atari disk drive.                    **
  78. //**                                    **
  79. //**    Inputs:                             **
  80. //**        freq - The atari sio data rate (ideally ~19034 bits per **
  81. //**        second) however, 18350bps seems to be more reliable.    **
  82. //**    Outputs:                            **
  83. //**        none.                            **
  84. //**                                    **
  85. //**    Routines called:                                **
  86. //**        none.                            **
  87. //**                                    **
  88. //**    History:                            **
  89. //**     07/11/94    Created            M.S.M.             **
  90. //**                                    **
  91. //**                                    **
  92. //************************************************************************
  93. void  calibrate(double freq)
  94. {
  95.    double tim, rate = (0.5/freq);        // get 1/2 the period
  96.    double clock_period = 1.0/1193180.0;
  97.    unsigned temp, inc= 0x80;            // start off with msb set
  98.    data_valid = 0x80;
  99.    long t;
  100.    outportb(97,1);                // enable timer 2
  101.    //*******use successive approximation method to estimate the loop count
  102.    for (int sa=0;sa<8;sa++)
  103.    {
  104.      t = 0L;
  105.      for (int i=0;i<N;i++)            // repeat inner loop N times
  106.      {
  107.      outportb(67,0xb4);                // set up counter 2 mode 2
  108.      asm {mov si,data_valid;}        // disable interrupts
  109.      outportb(66,0);            // reset timer
  110.      outportb(66,0);
  111. //     asm cli;                // For some reason disabling
  112.                         // interrupt messes up timing
  113.       Loop:
  114.      asm { dec si; jne Loop}                // decrement counter
  115. //     asm sti                // reenable interrupts
  116.      outportb(67,0x80);            // latch count
  117.      temp = inportb(66);
  118.      temp += (inportb(66)<<8);        // get count
  119.      t += long(-temp);
  120.       }
  121.       tim = double(t)*clock_period/N;                // get average loop time
  122.       if (tim>rate) data_valid -= inc;      // if the loop time is too
  123.       inc = inc>>1;                       // long, set current bit to zero.
  124.       data_valid |= inc;                        // try next lower bit
  125.  
  126. // for debug
  127. //      printf("tim = %lg, data_valid = %x\n", tim, data_valid);
  128.    }
  129.  
  130.    //Account for the instruction just before and just after the timing loop
  131.    data_valid = unsigned(double(data_valid)*0.98);
  132.  
  133.  
  134.    printf("\ncount error = %lg nS  loop count = %d\n", (tim-rate)*1e9, data_valid);
  135.    if (data_valid <75)  puts(
  136.        "The cpu clock is probably too slow for this program to work properly."
  137.     );
  138. }
  139.  
  140.  
  141. //************************************************************************
  142. //**    get_bytes(data,len,timeout)                    **
  143. //**        This routine expects to receive len bytes of data    **
  144. //**        over the atari SIO.                    **
  145. //**        The received data is stored in char near *data.        **
  146. //**        If the data is not received before timeout, then     **
  147. //**        the data buffer is filled with 0xff.                                    **
  148. //**                                    **
  149. //**    Inputs:                             **
  150. //**        data - A near pointer to the data buffer memory.    **
  151. //**        len  - The nember of bytes to be received, including    **
  152. //**            the checksum byte.                **
  153. //**        timeout - The routine waits timeout*8mS for a response.    **
  154. //**    Outputs:                            **
  155. //**        data - The data read from the serial bus is stored    **
  156. //**            in this memory space.  The first two bytes    **
  157. //**            are the acknowledge and complete bytes.        **
  158. //**            This is so that the calling routine can     **
  159. //**            can determine if the transfer was successful.    **
  160. //**                                    **
  161. //**    Routines called:                        **
  162. //**        none.                            **
  163. //**                                    **
  164. //**    History:                            **
  165. //**     07/11/94    Created            M.S.M.             **
  166. //**                                    **
  167. //**    Notes:                                **
  168. //**        1. The timing in this routine is critical.  Changes     **
  169. //**            should be made with extreme care.            **
  170. //**                                    **
  171. //**        2. The numbers in parenthesis are the 286 clock cycles     **
  172. //**            per instruction.                    **
  173. //************************************************************************
  174. void get_bytes(char near *data, int len, int timeout)
  175. {
  176.    // data - is the data buffer
  177.    // len - is the number of bytes to send
  178.    // timeout - is multiples of 8mS
  179.    asm {
  180.         cli            // I need exact timing (2)
  181.         mov    dx,37ah        // parallel control port (4)
  182.         mov    di,data        // get offset of data (21)
  183.         mov    bx,len        // initialize data counter (21)
  184.         mov    si,0        // set up time out timer (4)
  185.         mov    cx,timeout      // intialize timeout counter (21)
  186.        }
  187.     Data_Len_Loop:
  188.    asm {
  189.         dec    si        // dec timeout LSW counter (3)
  190.         jne    Wait_For_Data   // LSW timeout loop (4,16)
  191.         dec    cx        // dec timeout MSW counter (3)
  192.         je    P_DV_1        // jmp for time out error (4,16)
  193.        }
  194.    Wait_For_Data:
  195.    asm {
  196.         in    al,dx        // read PIO control port (8)
  197.         test    al,8        // isolate dataout bit  (4)
  198.         je    Data_Len_Loop    // wait for start bit  (4,16)
  199.         mov    cl,0        // cl holds received data (4)
  200.         mov    ch,9d        // data + start bit (4)
  201.        }
  202.     P_DV_1:
  203.    asm        mov    ax,data_valid    // start 26uS delay  (21)
  204.     DV_1:
  205.    asm {
  206.         dec    ax        // (4) clock delay
  207.         jne    DV_1        // (4,16) total delay = 20*delay_valid
  208.         shr    cl,1        // get ready for next bit (2)
  209.         in    al,dx        // read start bit (8)
  210.         shl    al,4        // make msb (11)
  211.         and    al,80h        // isolate dataout bit (4)
  212.         or    cl,al        // add bit to cl (3)
  213.         mov    ax,data_valid   // start 26uS delay (21)
  214.        }
  215.     DV_2:
  216.    asm {
  217.         dec    ax        // (4) clock delay
  218.         jne    DV_2        // (4,16) total delay = 20*delay_valid
  219.         dec    ch        // 10 bits (3)
  220.         jne    P_DV_1        // read next bit (4,16)
  221.         not    cl        // invert bits (3)
  222.         mov    ds:[di],cl    // save data (20)
  223.         inc    di        // data++ (3)
  224.         mov    ax,data_valid   // sync up to next bit (21)
  225.        }
  226.     DV_3:
  227.    asm {
  228.         dec     ax        // ~25uS counter (3)
  229.         jne    DV_3        // 25uS conunter loop (4,16)
  230.         dec    bx        // len--  (3)
  231.         mov    si,0        // setup timeout counter (4)
  232.         mov    cx,timeout    // (21)
  233.         jne    Data_Len_Loop    // loop back to get more bytes (4,16)
  234.         sti            // enable interrupts
  235.         // maximum time interrupts disabled <200ms
  236.        }
  237. }
  238. //************************************************************************
  239. //**    send_data(data,len)                        **
  240. //**        This routine sends len bytes of data over the atari SIO.**
  241. //**        The data is sent from the buffer pointed to by 'data'.    **
  242. //**        The command line is not toggled.            **
  243. //**                                    **
  244. //**    Inputs:                             **
  245. //**        data - A near pointer to the data buffer memory.    **
  246. //**        len  - The nember of bytes to be sent, including    **
  247. //**            the checksum byte.  The checksum byte must    **
  248. //**            be computed by the caller.            **
  249. //**    Outputs:                            **
  250. //**        data - The data read from the serial bus is stored    **
  251. //**            in this memory space.  These two bytes        **
  252. //**            are the 'acknowledge' and 'complete' bytes.    **
  253. //**            This is so that the calling routine can     **
  254. //**            can determine if the transfer was successful.    **
  255. //**                                    **
  256. //**    Routines called:                        **
  257. //**        none.                            **
  258. //**                                    **
  259. //**    History:                            **
  260. //**     07/11/94    Created            M.S.M.             **
  261. //**                                    **
  262. //**    Notes:                                **
  263. //**        1. The timing in this routine is critical.  Changes     **
  264. //**            should be made with extreme care.            **
  265. //**                                    **
  266. //**        2. The numbers in parenthesis are the 286 clock cycles     **
  267. //**            per instruction.                    **
  268. //************************************************************************
  269. void send_data(char *data, int len)
  270. {
  271.    asm {
  272.         cli            // I need exact timing (2)
  273.         mov    dx,37ah        // parallel control port (4)
  274.         mov    di,data        // get offset of data (21)
  275.         mov    si,len        // number of byte to send (21)
  276.         xor    bh,bh        // clear bh (3)
  277.        }
  278.     Data_Len_Loop:
  279.    asm {
  280.         mov    bl,[di]        // get send data from memory (21)
  281.         not    bl        // invert the data (3)
  282.         stc            // set start bit (2)
  283.         rcl    bx,2        // align data with proper pin (7)
  284.         mov    cx,10d        // data + start and stop bits (4)
  285.        }
  286.     Read_Next_Bit:
  287.    asm {
  288.         mov    ax,data_valid    // 26uS delay (21)
  289.        }
  290.     DV_1:
  291.    asm {
  292.         dec    ax        // (4) clock delay
  293.         jne    DV_1        // (4,16) jmp to finish delay
  294.         mov    al,bl        // get data (3)
  295.         and    al,2        // get data bit (4)
  296.         or    al,4        // rdy set (4)
  297.         out    dx,al        // send it out (10)
  298.         shr    bx,1        // get next bit (2)
  299.         mov    ax,data_xmit    // 26uS delay
  300.        }
  301.     DV_2:
  302.    asm {
  303.         dec    ax        // (4) clock delay
  304.         jne    DV_2        // (4,16) jmp to finish delay
  305.         dec    cx        // 10 bits (3)
  306.         jne    Read_Next_Bit    // read next bit (4,16)
  307.         mov    ax,data_valid    // 26uS delay (21)
  308.        }
  309.     DV_3:
  310.    asm {
  311.         dec    ax        // (4) clock delay
  312.         jne    DV_3        // (4,16) jmp to finish delay
  313.         inc    di        // data++
  314.         dec    si        // len--  (3)
  315.         jne    Data_Len_Loop    // get bytes (4,16)
  316.         sti            // enable interrupts
  317.         // maximum time interrupts disabled <200ms
  318.        }
  319.    get_bytes(data,2,5);
  320.  
  321. }
  322. //************************************************************************
  323. //**    send_frame(data)                        **
  324. //**        This routine sends 5 bytes of data over the atari SIO.    **
  325. //**        The data is sent from the buffer pointed to by 'data'.    **
  326. //**        The command line is toggled.                **
  327. //**                 ---                    **
  328. //**    Inputs:                             **
  329. //**        data - A near pointer to the data buffer memory.    **
  330. //**                                    **
  331. //**    Outputs:                            **
  332. //**        data - The data read from the serial bus is stored    **
  333. //**            in this memory space.  These two bytes        **
  334. //**            are the 'acknowledge' and 'complete' bytes.    **
  335. //**            This is so that the calling routine can     **
  336. //**            can determine if the transfer was successful.    **
  337. //**                                    **
  338. //**    Routines called:                        **
  339. //**        none.                            **
  340. //**                                    **
  341. //**    History:                            **
  342. //**     07/11/94    Created            M.S.M.             **
  343. //**                                    **
  344. //**    Notes:                                **
  345. //**        1. The timing in this routine is critical.  Changes     **
  346. //**            should be made with extreme care.            **
  347. //**                                    **
  348. //**        2. The numbers in parenthesis are the 286 clock cycles     **
  349. //**            per instruction.                    **
  350. //************************************************************************
  351. void send_frame(char *data)
  352. {
  353.    asm {
  354.         cli            // I need exact timing (2)
  355.         mov    dx,37ah        // parallel control port (4)
  356.         mov    di,data        // get offset of data (21)
  357.         mov    si,5        // number of byte to send (21)
  358.         xor    bh,bh        // clear bh (3)
  359.        }
  360.     Data_Len_Loop:
  361.    asm {
  362.         mov    bl,[di]        // get send data from memory (21)
  363.         not    bl        // invert the data (3)
  364.         stc            // set start bit (2)
  365.         rcl    bx,2        // align data with proper pin (7)
  366.         mov    cx,10d        // data + start and stop bits (4)
  367.        }
  368.     Read_Next_Bit:
  369.    asm {
  370.         mov    ax,data_valid    // 26uS delay (21)
  371.        }
  372.     DV_1:
  373.    asm {
  374.         dec    ax        // (4) clock delay
  375.         jne    DV_1        // (4,16) jmp to finish delay
  376.         mov    al,bl        // get data (3)
  377.         and    al,2        // get data bit (4)
  378.         or    al,5        // rdy and command set (4)
  379.         out    dx,al        // send it out (10)
  380.         shr    bx,1        // get next bit (2)
  381.         mov    ax,data_xmit    // 26uS delay
  382.        }
  383.     DV_2:
  384.    asm {
  385.         dec    ax        // (4) clock delay
  386.         jne    DV_2        // (4,16) jmp to finish delay
  387.         dec    cx        // 10 bits (3)
  388.         jne    Read_Next_Bit    // read next bit (4,16)
  389.         mov    ax,data_valid    // 26uS delay (21)
  390.        }
  391.     DV_3:
  392.    asm {
  393.         dec    ax        // (4) clock delay
  394.         jne    DV_3        // (4,16) jmp to finish delay
  395.         inc    di        // data++
  396.         dec    si        // len--  (3)
  397.         jne    Data_Len_Loop    // get bytes (4,16)
  398.         sti            // enable interrupts
  399.         // maximum time interrupts disabled <200ms
  400.        }
  401. }
  402.  
  403. //************************************************************************
  404. //**    frame_getdata(drive,command,aux1,aux2,timeout,data,len)        **
  405. //**        This routine sends a command frame over the atari SIO    **
  406. //**        and expects to 'len' bytes of receive data back.    **
  407. //**                                     **
  408. //**    Inputs:                             **
  409. //**        drive - Atari disk drive # 1 through 8.  (usually 1)    **
  410. //**        command - One of the atari SIO commands:        **
  411. //**            Read    0x52                    **
  412. //**            Write    0x57                    **
  413. //**            Status    0x53                    **
  414. //**            Put    0x50                    **
  415. //**            Format    0x21                    **
  416. //**            etc.                        **
  417. //**        aux1, aux2 - Same as SIO: value depends on command sent    **
  418. //**        timeout - Wait for response 'timeout'*8mS        **
  419. //**        data - A near pointer to the data buffer memory.    **
  420. //**        len  - The nember of bytes to be received, including    **
  421. //**            the checksum byte.                  **
  422. //**                                    **
  423. //**    Outputs:                            **
  424. //**        data - The data read from the serial bus is stored    **
  425. //**            in this memory space.  The first two bytes        **
  426. //**            are the 'acknowledge' and 'complete' bytes.    **
  427. //**            This is so that the calling routine can     **
  428. //**            can determine if the transfer was successful.    **
  429. //**                                    **
  430. //**    Routines called:                        **
  431. //**        send_frame()                        **
  432. //**        get_bytes()                        **
  433. //**                                    **
  434. //**    History:                            **
  435. //**     07/11/94    Created            M.S.M.             **
  436. //**                                    **
  437. //************************************************************************
  438. int frame_getdata(char drive, char command, char aux1, char aux2, int timeout,
  439.       char *data, int len)
  440. {
  441.    int check = 0;
  442.    outportb(0x37a,4);
  443.    data[0] = 0x30+drive;    // drive 1
  444.    data[1] = command;        // command
  445.    data[2] = aux1;        //  aux1
  446.    data[3] = aux2;        //  aux2
  447.    for (int i=0;i<4;i++)
  448.    {
  449.       check += data[i];
  450.       if (check>255) check -= 255;
  451.    }
  452.    data[4] = check;
  453.  
  454. //   puts("sending command frame");
  455.    outportb(0x37a,0x05);
  456.    asm {mov    ax,200;}
  457. loop1:
  458.    asm {dec ax; jne loop1}
  459.  
  460.    send_frame(data);        // send command frame
  461.    asm {mov ax,100;}
  462. loop2:
  463.    asm {dec ax; jne loop2}
  464.  
  465.    outportb(0x37a,0x04);
  466.    get_bytes(data,len+2,timeout);
  467. //   for (i=0;i<len+2;i++) printf("%x ", data[i]);
  468. //   puts("");
  469.  
  470.    return (data[0]==0x41);
  471. }
  472.  
  473. //************************************************************************
  474. //**    frame_senddata(drive,command,aux1,aux2,timeout,data,        **
  475. //**                        buff, bufflen)        **
  476. //**        This routine sends a command frame over the atari SIO    **
  477. //**        and then sends 'len' bytes of data.            **
  478. //**                                     **
  479. //**    Inputs:                             **
  480. //**        drive - Atari disk drive # 1 through 8.  (usually 1)    **
  481. //**        command - One of the atari SIO commands:        **
  482. //**            Read    0x52                    **
  483. //**            Write    0x57                    **
  484. //**            Status    0x53                    **
  485. //**            Put    0x50                    **
  486. //**            Format    0x21                    **
  487. //**            etc.                        **
  488. //**        aux1, aux2 - Same as SIO: value depends on command sent    **
  489. //**        timeout - Wait for response 'timeout'*8mS        **
  490. //**        data - A near pointer to the command buffer memory.    **
  491. //**        buff - A near pointer to the data buffer memory.    **
  492. //**        len  - The number of data bytes to be sent, including    **
  493. //**            the checksum byte.                  **
  494. //**                                    **
  495. //**    Outputs:                            **
  496. //**        data - The data read from the serial bus is stored    **
  497. //**            in this memory space.  These two bytes        **
  498. //**            are the 'acknowledge' and 'complete' bytes.    **
  499. //**            This is so that the calling routine can     **
  500. //**            can determine if the transfer was successful.    **
  501. //**                                    **
  502. //**    Routines called:                        **
  503. //**        send_frame()                        **
  504. //**        send_data()                        **
  505. //**                                    **
  506. //**    History:                            **
  507. //**     07/11/94    Created            M.S.M.             **
  508. //**                                    **
  509. //************************************************************************
  510. int frame_senddata(char drive, char command, char aux1, char aux2, char timeout,
  511.       char *data, char *buf, int lenbuf)
  512. {
  513.    int check = 0;
  514.    outportb(0x37a,4);
  515.    data[0] = 0x30+drive;    // drive 1
  516.    data[1] = command;        // command
  517.    data[2] = aux1;        //  aux1
  518.    data[3] = aux2;        //  aux2
  519.    for (int i=0;i<4;i++)
  520.    {
  521.       check+=data[i];
  522.       if (check>255) check -= 255;
  523.    }
  524.    data[4] = check;
  525. //   puts("sending command frame");
  526.    outportb(0x37a,0x05);
  527.    asm {mov    ax,200;}
  528. loop1:
  529.    asm {dec ax; jne loop1}
  530.  
  531.    send_frame(data);        // send command frame
  532.    asm {mov ax,100;}
  533. loop2:
  534.    asm {dec ax; jne loop2}
  535.  
  536.    outportb(0x37a,0x04);
  537.    get_bytes(data,1,timeout);
  538.  
  539.    send_data(buf,lenbuf);
  540.  
  541. //   printf("%x %x\n",data[0],data[1]);
  542.    return (data[0]==0x41);
  543. }
  544.  
  545. //************************************************************************
  546. //**    Main routine to copy an atari disk to the IBM harddrive.    **
  547. //**                                    **
  548. //**                                    **
  549. //**                                    **
  550. //**                                    **
  551. //************************************************************************
  552. void main(int argc, char **argv)
  553. {
  554.  
  555.    //**************Check for required command line inputs*************
  556.    if (argc<2) {
  557.       puts("**This program copy and entire atari disk to an ibm image file.**");
  558.       puts("usage:siocopy out_filename < -s, -e -d, or -2> <sio rate>");
  559.       puts("-s    single sided single density");
  560.       puts("-e    single sided enhanced density");
  561.       puts("-d    double sided double density");
  562.       puts("If sio rate not given, 19200 bits per second is used");
  563.       exit(0);
  564.    }
  565.  
  566.    // genreal purpose variables
  567.    unsigned i, check;
  568.  
  569.    // conatins the sio data rate
  570.    double siorate;
  571.  
  572.    //******* The data rate is adjustable to account for slightly ********
  573.    //******* different data rates on different atari disk drives.********
  574.    // get sio rate from command line or use default
  575.    if (argc>3) siorate = _atold(argv[3]);
  576.    else siorate = 19200.0;
  577.  
  578.    // Estimate the number of loop counts in 1/2 the period of the sio
  579.    // data rate.
  580.    printf("--- calibrating SIO data rate to %lg hz---\n", siorate);
  581.    calibrate(siorate);
  582.  
  583.    data_xmit = data_valid;    // used for debug
  584.    outportb(0x37a,4);        // initialize PIO lines
  585.  
  586.    // Try to read the disk drive status
  587.    if (frame_getdata(1,0x53,0,0,10,data, 5)==0)  // get four byte of status
  588.    {                        // plus one checksum byte
  589.       puts("Disk drive not responding: be sure the drive is connected and turned on.");
  590.       exit(0);
  591.    }
  592.  
  593.    // open IBM file
  594.    FILE *fout = fopen(argv[1],"wb");
  595.  
  596.    // Determine the atari disk drive type
  597.    int num_sect = 720, num_bytes = 128, read = 'R';
  598.    puts("reading atari disk drive #1");
  599.  
  600.    // if no drive specification is given, assume SSSD
  601.    if (argc>2)
  602.    {
  603.       argv[2]++;
  604.       switch(*argv[2])
  605.       {
  606.      // The user thinks it is an enhanced density disk.  Test it to
  607.      // be sure.
  608.      case 'e':
  609.      case 'E':
  610.      // Try to configure the disk drive
  611.         if (frame_senddata(1,0x4f,0,0,40,data,d1050,13)==0)
  612.         {
  613.            // disk is not configurable, maybe its a true 1050.
  614.            // Use the 1050 read command (I think this is correct).
  615.            read = 0x24;
  616.            num_sect = 1040;
  617.            break;
  618.         }
  619.  
  620.         // Read sector 1 from the disk
  621.         frame_getdata(1,'R',1,0,40,data,129);
  622.         delay(500);        // wait for rest of data if 256 byte/sector
  623.  
  624.         //Read confiuration record
  625.         frame_getdata(1,0x4e,0,0,40,data,13);
  626.         // Did it set up properly?
  627.         if (data[7]!=0x04)
  628.         {
  629.            puts("Not an enhanced density disk.");
  630.            num_sect = 720;
  631.         }
  632.         else num_sect = 1040;
  633.         break;
  634.      // Double density double sided case.
  635.      //*************************************************************
  636.      //*** This does not work.  I do not know the proper format ****
  637.      //*** for the double density case.                ****
  638.      //*************************************************************
  639.      case 'd':
  640.      case 'D':
  641.         if (frame_senddata(1,0x4f,0,0,40,data,xf551,13)==0)
  642.         {puts("This disk drive is not configurable."); exit(0);}
  643.  
  644.         //Read sector 1 to test data
  645.         frame_getdata(1,'R',1,0,40,data,129);
  646.         delay(500);        // wait for rest of data if 256 byte/sector
  647.  
  648.         // get configuration record.
  649.         frame_getdata(1,0x4e,0,0,40,data,13);
  650. //        for (i=0;i<13;i++) printf("%x ",data[i+2]);
  651. //        puts("");
  652.  
  653.         // Check if we have 256 byte sectors
  654.         if (data[8] == 1)
  655.            num_bytes = 256;
  656.         else
  657.         {
  658.            puts("not double density");
  659.            num_bytes = 128;
  660.         }
  661.         // Check if we have a two sided disk drive
  662.         if (data[6] == 1)
  663.            num_sect = 1040;
  664.         else
  665.         {
  666.            puts("not double sided");
  667.            num_sect = (data[7]==0)?720:1040;
  668.         }
  669.         break;
  670.      // Single sided single density case (atari 810)
  671.      case 's':
  672.      case 'S':
  673.         num_sect = 720;
  674.         frame_senddata(1,0x4f,0,0,10,data,d810,13);
  675.         break;
  676.     default:
  677.        puts("Drive type must be one of the following: <-s, -e, or -d>");
  678.        exit(0);
  679.     }
  680.    }
  681.  
  682.  
  683.    //read all the sectors
  684.    for (int sect=1;sect<=num_sect;sect++)
  685.    {
  686.       printf("reading   sector %d\r", sect);
  687.       if (frame_getdata(1,read,sect&0xff,sect>>8,2,data,num_bytes+1)==0)
  688.       puts("sector not read");
  689.  
  690.       // verify checksum
  691.       check = 0;
  692.       for (int k=0;k<num_bytes;k++)
  693.       {
  694.      check += data[k+2];
  695.      if (check>255) check -=255;
  696.       }
  697.       if (check!=data[num_bytes+2])
  698.       {printf("checksum error at sector %d.\n",sect);
  699.       puts("Bad disk, copy protected disk or wrong disk type");
  700.       exit(0);
  701.       }
  702.       // write the atari disk data to the ibm file
  703.       fwrite(&data[2],num_bytes,1,fout);
  704.    }
  705.    fclose(fout);
  706. }