int ARCH_MAINDECL main(int argc, char *argv[]) { int status = 0, id_ofs = 0, name_len; CBM_FILE fd; unsigned char drive, starttrack = 1, endtrack = 35, bump = 1, orig = 0; unsigned char verify = 0, demagnetize = 0, retries = 7; char cmd[40], name[20], *arg; struct FormatParameters parmBlock; int berror = 0; char *adapter = NULL; int option; struct option longopts[] = { { "help" , no_argument , NULL, 'h' }, { "version" , no_argument , NULL, 'V' }, { "adapter" , required_argument, NULL, '@' }, { "no-bump" , no_argument , NULL, 'n' }, { "extended" , no_argument , NULL, 'x' }, { "original" , no_argument , NULL, 'o' }, { "status" , no_argument , NULL, 's' }, { "verify" , no_argument , NULL, 'v' }, { "clear" , no_argument , NULL, 'c' }, { "retries" , required_argument, NULL, 'r' }, /* undocumented */ { "fillpattern", required_argument, NULL, 'f' }, { "begin-track", required_argument, NULL, 'b' }, { "end-track" , required_argument, NULL, 'e' }, { NULL , 0 , NULL, 0 } }; const char shortopts[] ="hVnxosvcr:f:b:e:@:"; while((option = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(option) { case 'n': bump = 0; break; case 'o': orig = 0x4b; break; case 's': status = 1; break; case 'x': starttrack = 1; endtrack = 40; break; case 'h': help(); return 0; #ifdef CBMFORNG case 'V': printf("cbmforng %s\n", OPENCBM_VERSION); #else case 'V': printf("cbmformat %s\n", OPENCBM_VERSION); #endif return 0; case 'v': verify = 1; break; case 'c': demagnetize = 1; break; case 'r': retries = arch_atoc(optarg); if(retries<1) retries= 1; else if(retries>63) retries=63; break; case 'f': orig = arch_atoc(optarg); break; case 'b': starttrack = arch_atoc(optarg); break; case 'e': endtrack = arch_atoc(optarg); break; case '@': if (adapter == NULL) adapter = cbmlibmisc_strdup(optarg); else { fprintf(stderr, "--adapter/-@ given more than once."); hint(argv[0]); return 1; } break; default : hint(argv[0]); return 1; } } if(optind + 2 != argc) { fprintf(stderr, "Usage: %s [OPTION]... DRIVE NAME,ID\n", argv[0]); hint(argv[0]); return 1; } arg = argv[optind++]; drive = arch_atoc(arg); if(drive < 8 || drive > 11) { fprintf(stderr, "Invalid drive number (%s)\n", arg); return 1; } arg = argv[optind++]; name_len = 0; while(*arg) { unsigned char c; c = (unsigned char) toupper(*arg); if(c == ',') { if(id_ofs) { fprintf(stderr, "More than one `,' in disk name\n"); return 1; } id_ofs = name_len; } name[name_len++] = c; if(name_len > 19) { fprintf(stderr, "Disk name too long\n"); return 1; } arg++; } name[name_len] = 0; if(name_len - id_ofs != 3) { fprintf(stderr, "Missing `,' in disk name or ID field not equal to two characters\n"); return 1; } if(cbm_driver_open_ex(&fd, adapter) == 0) { cbm_upload(fd, drive, 0x0300, dskfrmt, sizeof(dskfrmt)); prepareFmtPattern(&parmBlock, orig, endtrack, name[id_ofs+1], name[id_ofs+2]); parmBlock.P_STRCK=starttrack; // start track parameter parmBlock.P_ETRCK=endtrack+1; // end track parameter parmBlock.P_RETRY=(retries & ~0xC0) | (bump?0x40:0xC0); // number of retries (per disk, not per track) parmBlock.P_DOBMP=bump; // flag, if an initial head bump should be done parmBlock.P_DEMAG=demagnetize; // flag, if the disk should be demagnetized parmBlock.P_VRIFY=verify; // flag, if the disk should be verified #if 0 // for checking the generated format patterns { int j,k; for(j=0;j<34;j+=5) { for(k=0;k<5;k++) { printf(" $%02X", ((char *)(&parmBlock))[j+k]&0xFF); } printf("\n"); } printf(" $%02X\n", ((char *)(&parmBlock))[j]&0xFF); } #endif cbm_upload(fd, drive, 0x0200 - sizeof(parmBlock), ((char *)(&parmBlock)), sizeof(parmBlock)); sprintf(cmd, "M-E%c%c0:%s", 3, 3, name); cbm_exec_command(fd, drive, cmd, 7+name_len); berror = cbm_device_status(fd, drive, cmd, sizeof(cmd)); if(berror && status) { printf("%s\n", cmd); } #if defined(DebugFormat) && DebugFormat!=0 // verbose output { float RPMval; int sectors, virtGAPsze, remainder, trackTailGAP, flags, retry = 0, lastTr; const char *vrfy; unsigned char data[0x100]; // in case of an error, get the logging buffer from 0x0700 instead of 0x0500 if (cbm_download(fd, drive, berror?0x0700:0x0500, data, sizeof(data)) == sizeof(data)) { int i; printf("Track|Retry|sctrs|slctd|| GAP |modulo |modulo|tail| Verify | RPM |\n" " | | | GAP ||adjst|complmt| dvsr |GAP | | |\n" "-----+-----+-----+-----++-----+-------+------+----+---------+------+\n"); lastTr=-1; for (i=0; i < sizeof(data); i+=4) { if(data[i]==0) break; // no more data is available if(data[i]==lastTr) retry++; else retry=0; lastTr=data[i]; if(data[i]>=25) // preselect track dependent constants { if(data[i]>=31) sectors=17, RPMval=60000000.0f/16; else sectors=18, RPMval=60000000.0f/15; } else { if(data[i]>=18) sectors=19, RPMval=60000000.0f/14; else sectors=21, RPMval=60000000.0f/13; } // separate some flags flags=(data[i+3]>>6)&0x03; data[i+3]&=0x3f; switch(flags) { case 0x01: vrfy="SYNC fail"; break; case 0x02: vrfy=" OK "; break; case 0x03: vrfy="vrfy fail"; break; default: vrfy=" ./. "; } // recalculation of the track tail GAP out of the // choosen GAP for this track, the new GAP size // adjustment and the complement of the remainder // of the adjustment division virtGAPsze=data[i+1] -5; // virtual GAP increase to // prevent reformatting, when only one byte is missing // and other offset compensations remainder=((data[i+2]==0xff) ? virtGAPsze : sectors) - data[i+3]; trackTailGAP=((data[i+2]==0xff) ? 0 : data[i+2]*sectors + virtGAPsze) + remainder; // the following constants are nybble based (double the // size of the well known constants for SYNC lengths, // block header size, data block GAP and data block) // // (0x01&data[i+1]§ors) is a correction term, if "half // GAPs" are written and the number of sectors is odd // // RPMval / (sectors * (10+20+18+10 + 650 + data[i+1]) - (0x01&data[i+1]§ors) + trackTailGAP - data[i+1]) RPMval = (flags != 0x01) ? RPMval / (sectors * (10+20+18+10 + 650 + data[i+1]) - (0x01&data[i+1]§ors) + trackTailGAP - data[i+1]) : 0; printf(" %3u | ", data[i]); if(retry>0) printf("%3u", retry); else printf(" "); /* " |sctrs |slctd || GAP |modulo |modulo |tail | Verify | RPM |\n" * " | | GAP ||adjst |complmt | | GAP | | |\n" * "-+----- +----- ++----- +------- +------ +---- +---------+------+\n" */ printf(" | %2u |$%02X.%d||$%02X.%d| $%02X.%d | $%02X.%d|$%03X|%9s|%6.2f|\n", sectors, data[i+1]>>1, (data[i+1]<<3)&8, // selected GAP (((signed char)data[i+2])>>1)&0xFF, (data[i+2]<<3)&8, // GAP adjust data[i+3]>>1, (data[i+3]<<3)&8, // modulo complement remainder>>1, (remainder<<3)&8, // modulo (trackTailGAP>>1) + 1, // track tail GAP (with roundup) vrfy, RPMval); } printf("\n *) Note: The fractional parts of all the GAP based numbers shown here\n" " (sedecimal values) are given due to nybble based calculations.\n"); } else {
int ARCH_MAINDECL main(int argc, char *argv[]) { int status = 0, id_ofs = 0, name_len, i; CBM_FILE fd; // unsigned char drive, tracks = 35, bump = 1, orig = 0, show_progress = 0; unsigned char drive, tracks = 35, bump = 1, orig = 0x4b, show_progress = 0; char cmd[40], name[20], *arg; int erroroccured = 0; char *adapter = NULL; int option; struct option longopts[] = { { "help" , no_argument , NULL, 'h' }, { "version" , no_argument , NULL, 'V' }, { "adapter" , required_argument, NULL, '@' }, { "no-bump" , no_argument , NULL, 'n' }, { "extended" , no_argument , NULL, 'x' }, // { "original" , no_argument , NULL, 'o' }, { "fill" , required_argument, NULL, 'f' }, { "status" , no_argument , NULL, 's' }, { "progress" , no_argument , NULL, 'p' }, /* undocumented */ { "end-track" , required_argument, NULL, 't' }, { NULL , 0 , NULL, 0 } }; // const char shortopts[] ="hVnxospt:"; const char shortopts[] ="hVnxf:spt:"; while((option = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) { switch(option) { case 'n': bump = 0; break; case 'f': //orig = 0x4b; orig=arch_atoc(optarg); break; case 's': status = 1; break; case 'x': tracks = 40; break; case 'h': help(); return 0; case 'V': printf("frm_analyzer %s\n", OPENCBM_VERSION); return 0; case 'p': show_progress = 1; break; case 't': tracks = arch_atoc(optarg); break; case '@': if (adapter == NULL) adapter = cbmlibmisc_strdup(optarg); else { fprintf(stderr, "--adapter/-@ given more than once."); hint(argv[0]); return 1; } break; default : hint(argv[0]); return 1; } } if(optind + 2 != argc) { fprintf(stderr, "Usage: %s [OPTION]... DRIVE NAME,ID\n", argv[0]); hint(argv[0]); return 1; } arg = argv[optind++]; drive = arch_atoc(arg); if(drive < 8 || drive > 11) { fprintf(stderr, "Invalid drive number (%s)\n", arg); return 1; } arg = argv[optind++]; name_len = 0; while(*arg) { unsigned char c; c = (unsigned char) toupper(*arg); if(c == ',') { if(id_ofs) { fprintf(stderr, "More than one `,' in disk name\n"); return 1; } id_ofs = name_len; } name[name_len++] = c; if(name_len > 19) { fprintf(stderr, "Disk name too long\n"); return 1; } arg++; } name[name_len] = 0; if(cbm_driver_open_ex(&fd, adapter) == 0) { cbm_upload(fd, drive, 0x0300, dskfrmt, sizeof(dskfrmt)); sprintf(cmd, "M-E%c%c%c%c%c%c0:%s", 3, 3, tracks + 1, orig, bump, show_progress, name); cbm_exec_command(fd, drive, cmd, 11+strlen(name)); #if 0 if(show_progress) { /* do some handshake */ cbm_iec_release(fd, IEC_CLOCK); for(i = 1; i <= tracks; i++) { cbm_iec_wait(fd, IEC_DATA, 1); cbm_iec_set(fd, IEC_CLOCK); cbm_iec_wait(fd, IEC_DATA, 0); cbm_iec_release(fd, IEC_CLOCK); printf("#"); fflush(stdout); } printf("\n"); } #endif erroroccured = cbm_device_status(fd, drive, cmd, sizeof(cmd)); if(erroroccured && status) { printf("%s\n", cmd); } if(!erroroccured && (tracks > 35)) { cbm_open(fd, drive, 2, "#", 1); cbm_exec_command(fd, drive, "U1:2 0 18 0", 11); cbm_exec_command(fd, drive, "B-P2 192", 8); cbm_listen(fd, drive, 2); while(tracks > 35) { cbm_raw_write(fd, "\021\377\377\001", 4); tracks--; } cbm_unlisten(fd); cbm_exec_command(fd, drive, "U2:2 0 18 0", 11); cbm_close(fd, drive, 2); } if(!erroroccured && status) { cbm_device_status(fd, drive, cmd, sizeof(cmd)); printf("%s\n", cmd); } #if 1 // verbose output { #if 0 // @TODO unused variables float RPMval; int sectors, virtGAPsze, remainder, trackTailGAP, flags, retry, lastTr; const char *vrfy; #endif unsigned char data[0x100]; if (cbm_download(fd, drive, 0x0500, data, sizeof(data)) == sizeof(data)) { #if 1 // TODO, Pattern analyzer, get the lenght of the PLL synchronization period // // search the last byte triple consisting of: 0x49, 0x24, 0x92 // int k; const unsigned char pattern[]={0x49, 0x24, 0x92}; // const unsigned char pattern[]={0xdb, 0x6d, 0xb6}; for(k=sizeof(data)-3; k>=0; --k) { if(data[k]==pattern[0] && data[k+1]==pattern[1] && data[k+2]==pattern[2]) break; } if(k<0) { // no part of the written sequence was found k=sizeof(data); } else { // now search the beginning of that "010010010010010010010010..." bit stream while(k>=0 && data[k]==pattern[0] && data[k+1]==pattern[1] && data[k+2]==pattern[2]) { k-=3; } k+=3; // do single byte decreases if(k>=1 && data[k-1]==pattern[2]) --k; if(k>=1 && data[k-1]==pattern[1]) --k; if(k>=1 && data[k-1]==pattern[0]) --k; } printf("Result with Pattern: 0x%02X / %3d, formatted on track %2d, PLL synchronization length: %3d\n", orig, orig, tracks, k); for (i=0; i < sizeof(data); i++) { /* if(data[i] == 0) { printf("\n"); break; } */ printf(" %02X", data[i]); if((i&0x0f) == 0x0f) printf("\n"); } #else int i; printf("Track|Retry|sctrs|slctd|| GAP |modulo |modulo|tail| Verify | RPM |\n" " | | | GAP ||adjst|complmt| dvsr |GAP | | |\n" "-----+-----+-----+-----++-----+-------+------+----+---------+------+\n"); lastTr=-1; for (i=0; i < sizeof(data); i+=4) { if(data[i]==0) break; // no more data is available if(data[i+3]>=0x40 && data[i]>42){ // logging continuation line printf(" | | debug log || $%02X | $%02X $%02X $%02X\n", data[i], data[i+1], data[i+2], data[i+3]); continue; // proceed with next loop run } if(data[i]==lastTr) retry++; else retry=0; lastTr=data[i]; if(data[i]>=25) // preselect track dependent constants { if(data[i]>=31) sectors=17, RPMval=60000000.0f/16; else sectors=18, RPMval=60000000.0f/15; } else { if(data[i]>=18) sectors=19, RPMval=60000000.0f/14; else sectors=21, RPMval=60000000.0f/13; } // separate some flags flags=(data[i+3]>>6)&0x03; data[i+3]&=0x3f; switch(flags) { case 0x01: vrfy="SYNC fail"; break; case 0x02: vrfy="verify OK"; break; case 0x03: vrfy="vrfy fail"; break; default: vrfy=" ./. "; } // recalculation of the track tail GAP out of the // choosen GAP for this track, the new GAP size // adjustment and the complement of the remainder // of the adjustment division virtGAPsze=data[i+1] -3; // virtual GAP increase to // prevent reformatting, when only one byte is missing remainder=((data[i+2]==0xff) ? virtGAPsze : sectors) - data[i+3]; trackTailGAP=((data[i+2]==0xff) ? 0 : data[i+2]*sectors + virtGAPsze) + remainder; // the following constants are nybble based (double the // size of the well known constants for SYNC lengths, // block header size, data block GAP and data block) // // (0x01&data[i+1]§ors) is a correction term, if "half // GAPs" are written and the number of sectors is odd // // RPMval / (sectors * (10+20+18+10 + 650 + data[i+1]) - (0x01&data[i+1]§ors) + trackTailGAP - data[i+1]) RPMval = (flags != 0x01) ? RPMval / (sectors * (10+20+18+10 + 650 + data[i+1]) - (0x01&data[i+1]§ors) + trackTailGAP - data[i+1]) : 0; printf(" %3u | ", data[i]); if(retry>0) printf("%3u", retry); else printf(" "); /* " |sctrs |slctd || GAP |modulo |modulo |tail | Verify | RPM |\n" * " | | GAP ||adjst |complmt | |GAP | | |\n" * "-+----- +----- ++----- +------- +------ +---- +---------+------+\n" */ printf(" | %2u | $%02X || $%02X | $%02X | $%02X |$%03X|%9s|%6.2f|\n", sectors, data[i+1], data[i+2], data[i+3], remainder, trackTailGAP, vrfy, RPMval); } printf("\n *) Note: All GAP based numbers shown here (sedecimal values) are\n" " nybble based (4 GCR Bits) instead of GCR byte based.\n"); #endif } else {
static int measure_2cyleJitter(CBM_FILE HandleDevice, unsigned char DeviceAddress, unsigned char diskTrack, unsigned char sector, unsigned char count, GroupOfMeasurements *pDeltaGroup, int printDeltas) { char cmd[10]; unsigned char insts[40]; unsigned int mNo, timerValue, lastTvalue; #if _MINMAX_VALUES_PRINTOUT unsigned int dMin=~0, dMax=0; #endif struct Timer24bitValues T24Sample; SETSTATEDEBUG((void)0); #if _ASCII_PARAMETER_PASSING // must be: "Ux <track> <sector>" // sprintf(cmd, "U%c %d %d", ExecuteJobInBuffer, i, i & 0x0f); sprintf(cmd, "U%c %d %d", ExecuteJobInBuffer, diskTrack, sector); #else // must be: "Ux<track><sector>" with directly encoded bytes sprintf(cmd, "U%c%c%c", ExecuteJobInBuffer, diskTrack, sector); #endif pDeltaGroup->trueNumberOfIntervals = 0; // for each track do 1 initialisation and then // several measurements timerValue = 0; for(mNo = 0; mNo <= count; mNo++) { lastTvalue = timerValue; #if _ASCII_PARAMETER_PASSING if( cbm_exec_command(HandleDevice, DeviceAddress, cmd, strlen(cmd)) != 0) return 1; #else if( cbm_exec_command(HandleDevice, DeviceAddress, cmd, 4) != 0) return 1; #endif SETSTATEDEBUG((void)0); // wait for job to finish if( cbm_device_status(HandleDevice, DeviceAddress, insts, sizeof(insts)) ) { printf("%s\n", insts); } if( cbm_download(HandleDevice, DeviceAddress, timerShotMain, (unsigned char *) & T24Sample, sizeof(T24Sample)) != sizeof(T24Sample)) return 1; // read out sample that was shot by the jobcode timerValue = reconstruct_v32bitInc(T24Sample); if(mNo > 0){ lastTvalue = timerValue - lastTvalue; // increase by the number of overflows pDeltaGroup->trueNumberOfIntervals += (lastTvalue + 100000) / 200000; if( printDeltas ) printf("%6u ", lastTvalue); #if _MINMAX_VALUES_PRINTOUT if(lastTvalue > dMax) dMax = lastTvalue; if(lastTvalue < dMin) dMin = lastTvalue; #endif } else { pDeltaGroup->startValue = timerValue; if( printDeltas ) printf(" %10u ||", timerValue); } } #if _MINMAX_VALUES_PRINTOUT if( printDeltas ) printf(" %6u..%6u=%2u", dMin, dMax, dMax - dMin); #endif pDeltaGroup->endValue = timerValue; return 0; }