ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/readcbm.c
Revision: 1.3
Committed: 2004-01-10T14:05:59Z (20 years, 10 months ago) by cebix
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.2: +8 -8 lines
Log Message:
added support for 8050 and 8250 formats

File Contents

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