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, 3 months ago) by cebix
Content type: text/plain
Branch: MAIN
Branch point for: cebix
Log Message:
Initial revision

File Contents

# Content
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 }