ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/readcbm.c
Revision: 1.1
Committed: 2004-01-07T15:37:45Z (20 years, 2 months ago) by cebix
Content type: text/plain
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * readcbm.c - Read CBM disk to image file with the Catweasel controller
3     *
4     * Written in 2003 by Christian Bauer <Christian.Bauer@uni-mainz.de>
5     */
6    
7     #include <stdio.h>
8     #include <stdlib.h>
9     #include <string.h>
10     #include <time.h>
11     #include <unistd.h>
12     #include <errno.h>
13     #include <sys/io.h>
14    
15     #include "catweasel.h"
16     #include "common.h"
17    
18    
19     /* Raw track buffer and buffer pointer */
20     #define RAW_SIZE (128*1024)
21     static unsigned char raw_buf[RAW_SIZE];
22     static int buf_ptr = 0;
23    
24    
25     /* Search for next header sync, returns 0 if not found */
26     static int search_header_sync(void)
27     {
28     while (1) {
29    
30     // End of buffer reached? Then bail out
31     if (raw_buf[buf_ptr] & 0x80)
32     return 0;
33     if (buf_ptr > RAW_SIZE - 13)
34     return 0;
35    
36     // Header sync: 10 "1"-bits followed by GCR-encoded 0x08 (= 1111111112233)
37     if (raw_buf[buf_ptr + 0] == 1 && raw_buf[buf_ptr + 1] == 1
38     && raw_buf[buf_ptr + 2] == 1 && raw_buf[buf_ptr + 3] == 1
39     && raw_buf[buf_ptr + 4] == 1 && raw_buf[buf_ptr + 5] == 1
40     && raw_buf[buf_ptr + 6] == 1 && raw_buf[buf_ptr + 7] == 1
41     && raw_buf[buf_ptr + 8] == 1 && raw_buf[buf_ptr + 9] == 2
42     && raw_buf[buf_ptr + 10] == 2 && raw_buf[buf_ptr + 11] == 3
43     && raw_buf[buf_ptr + 12] == 3) {
44    
45     // Found, advance buffer pointer to header mark
46     buf_ptr += 9;
47     // fprintf(stderr, "Header found at %d\n", buf_ptr);
48     return 1;
49     }
50    
51     // Advance buffer pointer
52     buf_ptr++;
53     }
54     }
55    
56    
57     /* Search for next data sync, returns 0 if not found */
58     static int search_data_sync(void)
59     {
60     while (1) {
61    
62     // End of buffer reached? Then bail out
63     if (raw_buf[buf_ptr] & 0x80)
64     return 0;
65     if (buf_ptr > RAW_SIZE - 15)
66     return 0;
67    
68     // Data sync: 10 "1"-bits followed by GCR-encoded 0x07 (= 111111111222211)
69     if (raw_buf[buf_ptr + 0] == 1 && raw_buf[buf_ptr + 1] == 1
70     && raw_buf[buf_ptr + 2] == 1 && raw_buf[buf_ptr + 3] == 1
71     && raw_buf[buf_ptr + 4] == 1 && raw_buf[buf_ptr + 5] == 1
72     && raw_buf[buf_ptr + 6] == 1 && raw_buf[buf_ptr + 7] == 1
73     && raw_buf[buf_ptr + 8] == 1 && raw_buf[buf_ptr + 9] == 2
74     && raw_buf[buf_ptr + 10] == 2 && raw_buf[buf_ptr + 11] == 2
75     && raw_buf[buf_ptr + 12] == 2 && raw_buf[buf_ptr + 13] == 1
76     && raw_buf[buf_ptr + 14] == 1) {
77    
78     // Found, advance buffer pointer to data mark
79     buf_ptr += 9;
80     // fprintf(stderr, "Data found at %d\n", buf_ptr);
81     return 1;
82     }
83    
84     // Advance buffer pointer
85     buf_ptr++;
86     }
87     }
88    
89    
90     static const unsigned int gcr2bin_table_hi[32] = {
91     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
92     0xff, 0x80, 0x00, 0x10, 0xff, 0xc0, 0x40, 0x50,
93     0xff, 0xff, 0x20, 0x30, 0xff, 0xf0, 0x60, 0x70,
94     0xff, 0x90, 0xa0, 0xb0, 0xff, 0xd0, 0xe0, 0xff
95     };
96    
97     static const unsigned int gcr2bin_table_lo[32] = {
98     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
99     0xff, 0x08, 0x00, 0x01, 0xff, 0x0c, 0x04, 0x05,
100     0xff, 0xff, 0x02, 0x03, 0xff, 0x0f, 0x06, 0x07,
101     0xff, 0x09, 0x0a, 0x0b, 0xff, 0x0d, 0x0e, 0xff
102     };
103    
104     /* Decode GCR data to specified buffer */
105     static int decode_gcr(unsigned char *p, int num)
106     {
107     unsigned int r = 0;
108     int bit_count = 0;
109    
110     while (num > 0) {
111    
112     // Read clock value
113     unsigned char x = raw_buf[buf_ptr];
114    
115     // End of buffer reached? Then bail out
116     if (x & 0x80)
117     return 0;
118    
119     // Advance buffer pointer
120     buf_ptr++;
121    
122     // Assemble bits
123     r = (r << x) | 1;
124     bit_count += x;
125    
126     // 10 bits (= one GCR-encoded byte) assembled?
127     if (bit_count >= 10) {
128    
129     // Yes, write decoded byte to buffer
130     unsigned int gcr = (r >> (bit_count - 10)) & 0x3ff;
131     unsigned char bin_hi = gcr2bin_table_hi[gcr >> 5],
132     bin_lo = gcr2bin_table_lo[gcr & 0x1f];
133     *p++ = bin_hi | bin_lo;
134     num--;
135     bit_count -= 10;
136     }
137     }
138    
139     return 1;
140     }
141    
142    
143     /* Decode header and check for validity, returns 0 on error */
144     static int decode_header(int track, int *sector)
145     {
146     unsigned char header[6];
147     *sector = 0;
148    
149     // Decode header bytes
150     if (!decode_gcr(header, 6)) {
151     fprintf(stderr, "Track %d: buffer underrun reading header\n", track);
152     return 0;
153     }
154     // printf("hdr: %02x %02x %02x %02x %02x %02x\n", header[0], header[1], header[2], header[3], header[4], header[5]);
155    
156     // Check for validity
157     if (header[0] != 0x08) {
158     fprintf(stderr, "Track %d: invalid header mark (shouldn't happen)\n", track);
159     return 0;
160     }
161     if (header[1] ^ header[2] ^ header[3] ^ header[4] ^ header[5]) {
162     fprintf(stderr, "Track %d: header checksum incorrect\n", track);
163     // we'll try to continue anyways
164     }
165     if (header[2] >= num_sectors[track]) {
166     fprintf(stderr, "Track %d: invalid sector number in header\n", track);
167     return 0;
168     }
169     if (header[3] != track) {
170     fprintf(stderr, "Track %d: invalid track number in header (seek error?)\n", track);
171     return 0;
172     }
173    
174     // Everything seems OK, return sector number
175     *sector = header[2];
176     return 1;
177     }
178    
179    
180     /* Decode sector data to buffer, returns 0 on error */
181     static int decode_data(int track, int sector, unsigned char *p)
182     {
183     unsigned char tmp[SECTOR_SIZE + 2];
184     unsigned char sum = 0;
185     int i;
186    
187     // Decode data bytes
188     if (!decode_gcr(tmp, SECTOR_SIZE + 2)) {
189     fprintf(stderr, "Track %d sector %d: buffer underrun reading data\n", track, sector);
190     return 0;
191     }
192    
193     // Check for validity
194     if (tmp[0] != 0x07) {
195     fprintf(stderr, "Track %d sector %d: invalid data mark (shouldn't happen)\n", track, sector);
196     return 0;
197     }
198     for (i = 1; i < SECTOR_SIZE+2; i++)
199     sum ^= tmp[i];
200     if (sum) {
201     fprintf(stderr, "Track %d sector %d: data checksum incorrect\n", track, sector);
202     // we'll try to continue anyways
203     }
204    
205     // Copy data
206     memcpy(p, tmp + 1, SECTOR_SIZE);
207     return 1;
208     }
209    
210    
211     /* Decode sectors from raw_buf to track_buf */
212     static void decode_sectors(int track)
213     {
214     int sector;
215    
216     // No sector read yet
217     unsigned long sector_found = 0;
218     unsigned long all_sectors = (1 << num_sectors[track]) - 1;
219    
220     // Reset buffer pointer
221     buf_ptr = 0;
222    
223     // Process entire buffer
224     while (1) {
225    
226     // Search for next header sync
227     if (!search_header_sync())
228     break;
229    
230     // Decode sector header
231     if (decode_header(track, &sector)) {
232    
233     // Sector already read? Then don't do it again
234     if (sector_found & (1 << sector))
235     continue;
236    
237     // Search for next data sync
238     if (!search_data_sync())
239     break;
240    
241     // Decode sector data
242     if (decode_data(track, sector, track_buf + sector * SECTOR_SIZE)) {
243     sector_found |= 1 << sector;
244    
245     // All sectors read? Then we are done
246     if (sector_found == all_sectors)
247     break;
248     }
249     }
250     }
251    
252     // Check if all sectors of the track were found
253     if (sector_found != all_sectors) {
254     for (sector = 0; sector < num_sectors[track]; sector++)
255     if (!(sector_found & (1 << sector)))
256     fprintf(stderr, "Track %d: sector %d not found\n", track, sector);
257     }
258     }
259    
260    
261     /* Read one track into track_buf, returns 0 on error */
262     static int read_track(int drive, int track)
263     {
264     int i;
265    
266     // Set speed zone and tables
267     set_zone(track);
268    
269     // Seek to track
270     catweasel_seek(c.drives + drive, (track - 1) * (double_step + 1));
271     msdelay(20);
272    
273     // Clear buffer
274     memset(track_buf, 0, num_sectors[track] * SECTOR_SIZE);
275    
276     // Read track (1 revolution + 10%)
277     if (!catweasel_read(c.drives + drive, 0, 1, 1100 * 60 / drive_rpm)) {
278     fprintf(stderr, "Error reading track %d\n", track);
279     return 0;
280     }
281    
282     // Copy track data to buffer, apply thresholds
283     for (i = 0; i < RAW_SIZE; i++) {
284     unsigned char x = inb(c.io_mem), y;
285     if (x & 0x80) {
286     memset(raw_buf + i, 0x80, RAW_SIZE - i);
287     break;
288     }
289     if (x < thresh_table[0])
290     y = 0;
291     else if (x < thresh_table[1])
292     y = 1;
293     else if (x < thresh_table[2])
294     y = 2;
295     else
296     y = 3;
297     raw_buf[i] = y;
298     }
299     raw_buf[RAW_SIZE - 1] = 0x80;
300    
301     // Decode all sectors
302     decode_sectors(track);
303    
304     return 1;
305     }
306    
307    
308     int main(int argc, char **argv)
309     {
310     int port, drive, track;
311     FILE *f;
312    
313     // Parse arguments
314     if (argc != 4) {
315     fprintf(stderr, "Usage: %s <port> <drive> <file>\n", argv[0]);
316     return 1;
317     }
318    
319     port = strtol(argv[1], NULL, 16);
320     drive = atoi(argv[2]) & 1;
321    
322     // Open output file
323     f = fopen(argv[3], "wb");
324     if (f == NULL) {
325     fprintf(stderr, "Can't open %s for writing: %s\n", argv[3], strerror(errno));
326     return 1;
327     }
328    
329     // Obtain access to I/O ports
330     if (ioperm(port, 8, 1) == -1) {
331     fprintf(stderr, "No access to I/O ports\n");
332     return 1;
333     }
334     setuid(getuid());
335    
336     // Init Catweasel
337     memset(&c, 0, sizeof(c));
338     c.iobase = port;
339     c.msdelay = msdelay;
340     c.type = CATWEASEL_TYPE_MK1;
341     catweasel_init_controller(&c);
342    
343     // Start drive
344     catweasel_select(&c, drive == 0, drive == 1);
345     catweasel_set_motor(c.drives + drive, 1);
346     msdelay(500);
347     catweasel_seek(c.drives + drive, 0);
348     msdelay(20);
349    
350     // Read all tracks
351     for (track = 1; track <= NUM_TRACKS; track++) {
352     printf("Track %d...\n", track);
353     if (!read_track(drive, track))
354     break;
355     fwrite(track_buf, 256, num_sectors[track], f);
356     }
357    
358     // Stop drive
359     catweasel_set_motor(c.drives + drive, 0);
360     catweasel_select(&c, 0, 0);
361     catweasel_free_controller(&c);
362    
363     // Close output file
364     fclose(f);
365    
366     return 0;
367     }