1 /*
2 NIBREAD - part of the NIBTOOLS package for 1541/1571 disk image nibbling
3 by Peter Rittwage <peter(at)rittwage(dot)com>
4 based on code from MNIB, by Dr. Markus Brenner
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <signal.h>
11 #include <time.h>
12 #include <ctype.h>
13
14 #include "mnibarch.h"
15 #include "gcr.h"
16 #include "nibtools.h"
17 #include "lz.h"
18
19 int _dowildcard = 1;
20
21 char bitrate_range[4] = { 43 * 2, 31 * 2, 25 * 2, 18 * 2 };
22 char bitrate_value[4] = { 0x00, 0x20, 0x40, 0x60 };
23 char density_branch[4] = { 0xb1, 0xb5, 0xb7, 0xb9 };
24
25 BYTE compressed_buffer[(MAX_HALFTRACKS_1541 + 2) * NIB_TRACK_LENGTH];
26 BYTE file_buffer[(MAX_HALFTRACKS_1541 + 2) * NIB_TRACK_LENGTH];
27 BYTE track_buffer[(MAX_HALFTRACKS_1541 + 2) * NIB_TRACK_LENGTH];
28 BYTE track_density[MAX_HALFTRACKS_1541 + 2];
29 BYTE track_alignment[MAX_HALFTRACKS_1541 + 2];
30 size_t track_length[MAX_HALFTRACKS_1541 + 2];
31
32 size_t error_retries;
33 int file_buffer_size;
34 int reduce_sync, reduce_badgcr, reduce_gap;
35 int fix_gcr;
36 int start_track, end_track, track_inc;
37 int read_killer;
38 int align;
39 int drivetype;
40 int imagetype;
41 int mode;
42 int force_density;
43 int track_match;
44 int gap_match_length;
45 int cap_min_ignore;
46 int interactive_mode;
47 int verbose;
48 int extended_parallel_test;
49 int force_nosync;
50 int ihs;
51 int auto_capacity_adjust;
52 int align_disk;
53 int skew;
54 int rawmode;
55 int rpm_real;
56 int unformat_passes;
57 int capacity_margin;
58 int align_delay;
59 int align_report;
60 int increase_sync = 0;
61 int presync = 0;
62 BYTE fillbyte = 0x55;
63 BYTE drive = 8;
64 char * cbm_adapter = "";
65 int use_floppycode_srq = 0;
66 int override_srq = 0;
67 int extra_capacity_margin=5;
68 int sync_align_buffer=0;
69 int fattrack=0;
70 int old_g64=0;
71
72 BYTE density_map;
73 float motor_speed;
74
75 CBM_FILE fd;
76 FILE *fplog;
77
78 int ARCH_MAINDECL
main(int argc,char * argv[])79 main(int argc, char *argv[])
80 {
81 int bump, reset, i;
82 char filename[256], logfilename[256], *dotpos;
83 char argcache[256];
84 FILE *fp;
85
86 fprintf(stdout,
87 "\nnibread - Commodore 1541/1571 disk image nibbler\n"
88 AUTHOR "Revision %d - " VERSION "\n\n", SVN);
89
90 /* we can do nothing with no switches */
91 if (argc < 2)
92 usage();
93
94 /* clear heap buffers */
95 memset(compressed_buffer, 0x00, sizeof(compressed_buffer));
96 memset(file_buffer, 0x00, sizeof(file_buffer));
97 memset(track_buffer, 0x00, sizeof(track_buffer));
98
99 #ifdef DJGPP
100 fd = 1;
101 #endif
102
103 bump = 1; /* failing to bump sometimes give us wrong tracks on heavily protected disks */
104 reset = 1;
105
106 start_track = 1 * 2;
107 end_track = 41 * 2;
108 track_inc = 2;
109
110 reduce_sync = 4;
111 reduce_badgcr = 0;
112 reduce_gap = 0;
113 fix_gcr = 0;
114 read_killer = 1;
115 error_retries = 10;
116 force_density = 0;
117 track_match = 0;
118 interactive_mode = 0;
119 verbose = 1;
120 extended_parallel_test = 0;
121 force_nosync = 0;
122 align = ALIGN_NONE;
123 gap_match_length = 7;
124 cap_min_ignore = 0;
125 ihs = 0;
126 mode = MODE_READ_DISK;
127 rpm_real = 296;
128 align_report = 0;
129
130 // cache our arguments for logfile generation
131 strcpy(argcache, "");
132 for (i = 0; i < argc; i++)
133 {
134 strcat(argcache, argv[i]);
135 strcat(argcache," ");
136 }
137
138 // parse arguments
139 while (--argc && (*(++argv)[0] == '-'))
140 {
141 switch ((*argv)[1])
142 {
143 case '@':
144 cbm_adapter = &(*argv)[2];
145 printf("* Using OpenCBM adapter %s\n", cbm_adapter);
146 break;
147
148 case 'P':
149 printf("* Skip 1571 SRQ Support (Use parallel)\n");
150 override_srq = 1;
151 break;
152
153 case 's':
154 break;
155
156 case 'j':
157 printf("* 1541/1571 Index Hole Sensor (SC+ compatible)\n");
158 Use_SCPlus_IHS = 1;
159 use_floppycode_ihs = 1; // ihs floppy code!
160 break;
161
162 case 'x':
163 printf("* Track Alignment Report (1541/1571 SC+ compatible IHS)\n");
164 track_align_report = 1;
165 use_floppycode_ihs = 1; // ihs floppy code!
166 break;
167
168 case 'y':
169 printf("* Deep Bitrate Scan (1541/1571 SC+ compatible IHS)\n");
170 Deep_Bitrate_SCPlus_IHS = 1;
171 use_floppycode_ihs = 1; // ihs floppy code!
172 break;
173
174 case 'z':
175 printf("* Testing 1541/1571 Index Hole Sensor (SC+ compatible)\n");
176 Test_SCPlus_IHS = 1;
177 bump = 0; // Don't bump for simple IHS check
178 use_floppycode_ihs = 1; // ihs floppy code!
179 break;
180
181 case 'A':
182 align_report = 1;
183 printf("* Track Alignment Report\n");
184 break;
185
186 case 'h':
187 track_inc = 1;
188 end_track = 83;
189 printf("* Using halftracks\n");
190 break;
191
192 case 'i':
193 printf("* 1571 or SuperCard-compatible index hole sensor (use only for side 1)\n");
194 ihs = 1;
195 break;
196
197 case 'V':
198 track_match = 1;
199 printf("* Enable track match (low-level verify)\n");
200 break;
201
202 case 'n':
203 force_nosync = 0;
204 printf("* Allowing track reads to wait for sync\n");
205 break;
206
207 case 't':
208 extended_parallel_test = atoi(&(*argv)[2]);
209 if(!extended_parallel_test)
210 extended_parallel_test = 100;
211 printf("* Extended parallel port test loops = %d\n", extended_parallel_test);
212 break;
213
214 case 'I':
215 interactive_mode = 1;
216 printf("* Interactive mode\n");
217 break;
218
219 case 'd':
220 force_density = 1;
221 printf("* Forcing default density\n");
222 break;
223
224 case 'k':
225 read_killer = 0;
226 printf("* Disabling read of 'killer' tracks\n");
227 break;
228
229 case 'S':
230 if (!(*argv)[2]) usage();
231 start_track = (BYTE) (2*(atoi(&(*argv)[2])));
232 printf("* Start track set to %d\n", start_track/2);
233 break;
234
235 case 'E':
236 if (!(*argv)[2]) usage();
237 end_track = (BYTE) (2*(atoi(&(*argv)[2])));
238 printf("* End track set to %d\n", end_track/2);
239 break;
240
241 case 'D':
242 if (!(*argv)[2]) usage();
243 drive = (BYTE) (atoi(&(*argv)[2]));
244 printf("* Use Device %d\n", drive);
245 break;
246
247 case 'G':
248 if (!(*argv)[2]) usage();
249 gap_match_length = atoi(&(*argv)[2]);
250 printf("* Gap match length set to %d\n", gap_match_length);
251 break;
252
253 case 'v':
254 verbose++;
255 printf("* Verbose mode on\n");
256 break;
257
258 case 'e': // change read retries
259 if (!(*argv)[2]) usage();
260 error_retries = atoi(&(*argv)[2]);
261 printf("* Read retries set to %d\n", error_retries);
262 break;
263
264 case 'm':
265 printf("* Minimum capacity ignore on\n");
266 cap_min_ignore = 1;
267 break;
268
269 default:
270 usage();
271 break;
272 }
273 }
274 printf("\n");
275
276 if(argc < 1) usage();
277 strcpy(filename, argv[0]);
278
279 if( (fp=fopen(filename,"r")) )
280 {
281 fclose(fp);
282 printf("File exists - Overwrite? (y/N)");
283 if(getchar() != 'y') exit(0);
284 }
285
286 #ifdef DJGPP
287 calibrate();
288 if (!detect_ports(reset))
289 return 0;
290 #elif defined(OPENCBM_42)
291 /* remain compatible with OpenCBM < 0.4.99 */
292 if (cbm_driver_open(&fd, 0) != 0)
293 {
294 printf("Is your X-cable properly configured?\n");
295 exit(0);
296 }
297 #else /* assume > 0.4.99 */
298 if (cbm_driver_open_ex(&fd, cbm_adapter) != 0)
299 {
300 printf("Is your X-cable properly configured?\n");
301 exit(0);
302 }
303 #endif
304
305 /* Once the drive is accessed, we need to close out state when exiting */
306 atexit(handle_exit);
307 signal(SIGINT, handle_signals);
308
309 if(!init_floppy(fd, drive, bump))
310 {
311 printf("Floppy drive initialization failed\n");
312 exit(0);
313 }
314
315 if(extended_parallel_test)
316 parallel_test(extended_parallel_test);
317
318 if (Test_SCPlus_IHS) // "-z"
319 {
320 IHSresult = Check_SCPlus_IHS(fd,0); // 0=TurnIHSoffAfterwards
321 OutputIHSResult(TRUE,FALSE,IHSresult,NULL);
322 exit(0);
323 }
324
325 if(align_report)
326 TrackAlignmentReport(fd);
327
328 /* create log file */
329 strcpy(logfilename, filename);
330 dotpos = strrchr(logfilename, '.');
331 if (dotpos != NULL)
332 *dotpos = '\0';
333 strcat(logfilename, ".log");
334
335 if ((fplog = fopen(logfilename, "wb")) == NULL)
336 {
337 fprintf(stderr, "Couldn't create log file %s!\n", logfilename);
338 exit(2);
339 }
340
341 fprintf(fplog, "%s\n", VERSION);
342 fprintf(fplog, "'%s'\n", argcache);
343
344 if(strrchr(filename, '.') == NULL) strcat(filename, ".nbz");
345
346 if((compare_extension(filename, "D64")) || (compare_extension(filename, "G64")))
347 {
348 printf("\nDisk imaging only directly supports NIB, NB2, and NBZ formats.\n");
349 printf("Use nibconv after imaging to convert to desired file type.\n");
350 exit(0);
351 }
352
353 if (Use_SCPlus_IHS) // "-j"
354 {
355 IHSresult = Check_SCPlus_IHS(fd,1); // 1=KeepOn
356 OutputIHSResult(TRUE,TRUE,IHSresult,fplog);
357 if (IHSresult != 0)
358 {
359 // turn SCPlus IHS off
360 send_mnib_cmd(fd, FL_IHS_OFF, NULL, 0);
361 burst_read(fd);
362
363 if (fplog) fclose(fplog);
364 exit(0);
365 }
366 }
367
368
369 if (Deep_Bitrate_SCPlus_IHS) // "-y"
370 {
371 // We need some memory for the Deep Bitrate Scan
372 if(!(logline = malloc(0x10000)))
373 {
374 printf("Error: Could not allocate memory for Deep Bitrate Scan buffer.\n");
375 exit(0);
376 }
377 DeepBitrateAnalysis(fd,filename,track_buffer,logline);
378 }
379 else if (track_align_report) // "-x"
380 TrackAlignmentReport2(fd,track_buffer);
381 else
382 {
383 if(!(disk2file(fd, filename)))
384 printf("Operation failed!\n");
385 }
386
387
388 if (Use_SCPlus_IHS) // "-j"
389 {
390 // turn SCPlus IHS off
391 send_mnib_cmd(fd, FL_IHS_OFF, NULL, 0);
392 burst_read(fd);
393 }
394
395 motor_on(fd);
396 step_to_halftrack(fd, 18*2);
397
398 if(fplog) fclose(fplog);
399
400 exit(0);
401 }
402
parallel_test(int iterations)403 void parallel_test(int iterations)
404 {
405 int i;
406
407 printf("Performing extended parallel port test\n");
408 for(i=0; i<iterations; i++)
409 {
410 if(!verify_floppy(fd))
411 {
412 printf("Parallel port failed extended testing. Check wiring and sheilding.\n");
413 exit(0);
414 }
415 printf(".");
416 }
417 printf("\nPassed advanced parallel port test\n");
418 exit(0);
419 }
420
disk2file(CBM_FILE fd,char * filename)421 int disk2file(CBM_FILE fd, char *filename)
422 {
423 int count = 0;
424 char newfilename[256];
425 char filenum[4], *dotpos;
426
427 /* read data from drive to file */
428 motor_on(fd);
429
430 if(compare_extension(filename, "NB2"))
431 {
432 track_inc = 1;
433 if(!(write_nb2(fd, filename))) return 0;
434 }
435 else if(compare_extension(filename, "NIB"))
436 {
437 if(!(read_floppy(fd, track_buffer, track_density, track_length))) return 0;
438 if(!(file_buffer_size = write_nib(file_buffer, track_buffer, track_density, track_length))) return 0;
439 if(!(save_file(filename, file_buffer, file_buffer_size))) return 0;
440
441 if(interactive_mode)
442 {
443 for(;;)
444 {
445 motor_off(fd);
446 printf("Swap disk and press a key for next image, or CTRL-C to quit.\n");
447 getchar();
448 motor_on(fd);
449
450 /* create new filename */
451 sprintf(filenum, "%d", ++count);
452 strcpy(newfilename, filename);
453 dotpos = strrchr(newfilename, '.');
454 if (dotpos != NULL) *dotpos = '\0';
455 strcat(newfilename, filenum);
456 strcat(newfilename, ".nib");
457
458 if(!(read_floppy(fd, track_buffer, track_density, track_length))) return 0;
459 if(!(file_buffer_size = write_nib(file_buffer, track_buffer, track_density, track_length))) return 0;
460 if(!(save_file(newfilename, file_buffer, file_buffer_size))) return 0;
461 }
462 }
463 }
464 else
465 {
466 if(!(read_floppy(fd, track_buffer, track_density, track_length))) return 0;
467 if(!(file_buffer_size = write_nib(file_buffer, track_buffer, track_density, track_length))) return 0;
468 if(!(file_buffer_size = LZ_CompressFast(file_buffer, compressed_buffer, file_buffer_size))) return 0;
469 if(!(save_file(filename, compressed_buffer, file_buffer_size))) return 0;
470
471 if(interactive_mode)
472 {
473 for(;;)
474 {
475 motor_off(fd);
476 printf("Swap disk and press a key for next image, or CTRL-C to quit.\n");
477 getchar();
478 motor_on(fd);
479
480 /* create new filename */
481 sprintf(filenum, "%d", ++count);
482 strcpy(newfilename, filename);
483 dotpos = strrchr(newfilename, '.');
484 if (dotpos != NULL) *dotpos = '\0';
485 strcat(newfilename, filenum);
486 strcat(newfilename, ".nbz");
487
488 if(!(read_floppy(fd, track_buffer, track_density, track_length))) return 0;
489 if(!(file_buffer_size = write_nib(file_buffer, track_buffer, track_density, track_length))) return 0;
490 if(!(file_buffer_size = LZ_CompressFast(file_buffer, compressed_buffer, file_buffer_size))) return 0;
491 if(!(save_file(newfilename, compressed_buffer, file_buffer_size))) return 0;
492 }
493 }
494 }
495
496 return 1;
497 }
498
499 void
usage(void)500 usage(void)
501 {
502 fprintf(stderr, "usage: nibread [options] <filename>\n\n"
503 " -@x: Use OpenCBM device 'x' (xa1541, xum1541:0, xum1541:1, etc.)\n"
504 " -D[n]: Use drive #[n]\n"
505 " -e[n]: Retry reading tracks with errors [n] times\n"
506 " -S[n]: Override starting track\n"
507 " -E[n]: Override ending track\n"
508 " -G[n]: Match track gap by [n] number of bytes (advanced users only)\n"
509 " -s: Use SRQ transfer code instead of parallel (1571 only)\n"
510 " -k: Disable reading of 'killer' tracks\n"
511 " -d: Force default densities\n"
512 " -v: Enable track matching (crude read verify)\n"
513 " -I: Interactive imaging mode\n"
514 // " -m: Disable minimum capacity check\n"
515 " -V: Verbose (output more detailed track data)\n"
516 " -h: Read halftracks\n"
517 " -t: Extended parallel port tests\n"
518 " -j: Use Index Hole Sensor (1541/1571 SC+ compatible IHS)\n"
519 " -x: Track Alignment Report (1541/1571 SC+ compatible IHS)\n"
520 " -y: Deep Bitrate Analysis (1541/1571 SC+ compatible IHS)\n"
521 " -z: Test Index Hole Sensor (1541/1571 SC+ compatible IHS)\n"
522 );
523 exit(1);
524 }
525