Added initial Macintosh source.

This commit is contained in:
Marcio T 2021-11-23 11:50:09 -07:00
parent d3351d0ece
commit b38e259105
43 changed files with 2278 additions and 3 deletions

View File

@ -11,9 +11,6 @@ This tool is meant for Macintosh computers with a SCSI port, which
range from the Macintosh Plus, released in 1986, through the "Beige"
Power Macintosh G3, released in 1997.
If you have consulting work, particular contract work pertaining
to vintage computers, please hit me via my GitHub account!
Disclaimer
----------
@ -30,6 +27,12 @@ Right now the port is in early testing, so I am not releasing any
compiled binaries. There is always a risk of data loss with a tool like
this, so please contact me directly if you want to beta test.
Got projects?
-------------
If you have consulting work, particular contract work pertaining
to vintage computers or THREE.js, please hit me via my [GitHub account]!
About the code
--------------
@ -59,6 +62,7 @@ his code in this repository with his permission.
</details>
[GitHub account]: https://github.com/marciot
[mac-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip1.png "TIP"
[win-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/win-tip1.gif "TIP"
[win-screenshot2]: https://github.com/marciot/mac-tip/raw/main/images/win-tip2.gif "TIP"

Binary file not shown.

Binary file not shown.

BIN
mac-cpp-source/.finf/macos Normal file

Binary file not shown.

BIN
mac-cpp-source/.finf/scsi Normal file

Binary file not shown.

BIN
mac-cpp-source/.finf/tip Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,176 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <SIOUX.h>
#include "tip.h"
#include "mac_vol.h"
#include "mac_scsi.h"
#include "iomega_cmds.h"
bool process_command();
void printn( unsigned char *c, int n );
void print_help();
void scan_bus();
void dev_info( int id );
void show_spares( int id );
void main() {
SIOUXSettings.autocloseonquit = TRUE;
SIOUXSettings.asktosaveonclose = FALSE;
SIOUXSettings.standalone = FALSE;
printf( "SCSI and Iomega Zip/Jaz Toolkit V0.1\n" );
printf( "(c) 2021 Marcio Teixeira\n\n" );
printf( "TIP based on source code provided by Steve Gibson (http://grc.com)\n" );
SIOUXSetTitle("\pCommand Console");
print_help();
do {
EventRecord event;
if (WaitNextEvent(everyEvent, &event, GetCaretTime(), NULL))
SIOUXHandleOneEvent(&event);
} while (process_command());
printf( "Goodbye.\n" );
}
bool process_command() {
short int arg_val = 0;
char cmd[80];
printf( "\n> " );
gets( cmd );
printf("\n");
char *arg_str = strchr(cmd, ' ');
if(arg_str) arg_val = atoi(arg_str);
switch( tolower(cmd[0]) ) {
case 'h': print_help(); break;
case 'l': scan_bus(); break;
case 's': iomega_spin_up_cartridge(arg_val); break;
case 'r': scsi_reset(); break;
case 'e': iomega_eject_cartridge(arg_val); break;
case 'i': dev_info(arg_val); break;
case 'v': mac_list_volumes(); break;
case 'u': mac_unmount(arg_val); break;
case 't': run_tip(); break;
case 'q': return false;
}
return true;
}
void print_help() {
printf(
"\nGeneral commands:\n"
" help : print this help\n"
" quit : quit the program\n"
"\nMacintosh commands (please unmount Zip prior to testing):\n"
" volumes : list Mac volumes\n"
" unmount [n] : unmount a volume\n"
"\nGeneral SCSI operations:\n"
" reset : reset the SCSI bus\n"
" list : list devices on the SCSI bus\n"
" info [n] : display SCSI inquiry\n"
"\nIomega device operations on SCSI device:\n"
" spin [n] : spin up a cartridge\n"
" eject [n] : eject cartridge\n"
" tip [n] : run Steve Gibson's TIP 2.1\n"
);
}
void scan_bus() {
short err, id;
scsi_inq_reply reply;
for( id=0; id<8; id++ ) {
err = scsi_inquiry( id, 0, &reply);
if( err != 0 ) {
printf( " %hd: (Not installed)\n", id );
} else {
printf( " %hd: ", id );
printn( reply.prod, 16 );
printf( " " );
printn( reply.vend, 8 );
printf( " " );
printn( reply.rvsn, 4 );
putchar( '\n' );
}
}
}
void dev_info( int id ) {
short err, lun;
scsi_inq_reply reply;
for( lun = 0; lun < 8; lun++ ) {
err = scsi_inquiry( id, lun, &reply);
if( err ) {
printf( "Device not installed\n" );
return;
}
printf( " LUN %hd: ", lun );
switch( (reply.inf1 & 0xE0) >> 5 ) {
case 0x00: printf( "supported and connected\n" ); break;
case 0x01: printf( "not connected\n" ); continue;
case 0x03: printf( "not supported\n" ); continue;
}
printf( " Device class (%02X): ", reply.inf1 & 0x1F );
switch( reply.inf1 & 0x1F ) {
case 0x00: printf( "Disk drive\n" ); break;
case 0x01: printf( "Tape drive\n" ); break;
case 0x02: printf( "Printer\n" ); break;
case 0x03: printf( "Processor device\n" ); break;
case 0x04: printf( "WORM drive\n" ); break;
case 0x05: printf( "CD-ROM drive\n" ); break;
case 0x06: printf( "Scanner\n" ); break;
case 0x07: printf( "Optical disk\n" ); break;
case 0x08: printf( "Media changer\n" ); break;
case 0x09: printf( "Communication device\n" ); break;
case 0x1F: printf( "Unknown device\n" ); break;
default: printf( "Reserved\n" );
}
printf( " ANSI version (%02X): ", reply.vers & 0x07 );
switch( reply.vers & 0x07 ) {
case 0x00: printf( "SCSI-1\n" ); break;
case 0x01: printf( "SCSI-1 w/ CCS\n" ); break;
case 0x02: printf( "SCSI-2\n" ); break;
default: printf( "???\n" );
}
printf( " ISO version (%02X)\n", reply.vers & 0xC0 >> 6 );
printf( " ECMA version (%02X)\n", reply.vers & 0x78 >> 3 );
printf( " Flags: " );
if( reply.flg1 & 0x80 ) printf( "rmb " );
if( reply.flg2 & 0x80 ) printf( "rel " );
if( reply.flg2 & 0x40 ) printf( "w32 " );
if( reply.flg2 & 0x20 ) printf( "w16 " );
if( reply.flg2 & 0x10 ) printf( "syn " );
if( reply.flg2 & 0x08 ) printf( "lnk " );
if( reply.flg2 & 0x04 ) printf( "??? " );
if( reply.flg2 & 0x02 ) printf( "que " );
if( reply.flg2 & 0x01 ) printf( "sfR " );
if( reply.inf2 & 0x80 ) printf( "aen " );
if( reply.inf2 & 0x40 ) printf( "tio " );
printf( "\n" );
}
}
void printn( unsigned char *c, int n ) {
while( n-- ) {
putchar( isprint(*c) ? *c : '.' );
c++;
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

View File

@ -0,0 +1,38 @@
#include <stdio.h>
#include <Files.h>
#include "mac_vol.h"
void mac_list_volumes() {
HParamBlockRec paramBlock;
Str255 volName;
paramBlock.volumeParam.ioCompletion = 0;
paramBlock.volumeParam.ioNamePtr = volName;
paramBlock.volumeParam.ioVRefNum = 0;
paramBlock.volumeParam.ioVolIndex = 0;
for (;;) {
OSErr err = PBHGetVInfo(&paramBlock, false);
if (err == nsvErr) break;
printf(" %d: %#s\n", paramBlock.volumeParam.ioVolIndex, paramBlock.volumeParam.ioNamePtr);
paramBlock.volumeParam.ioVolIndex++;
}
}
void mac_unmount(int id) {
HParamBlockRec paramBlock;
paramBlock.volumeParam.ioCompletion = 0;
paramBlock.volumeParam.ioNamePtr = 0;
paramBlock.volumeParam.ioVRefNum = 0;
paramBlock.volumeParam.ioVolIndex = id;
OSErr err = PBHGetVInfo(&paramBlock, false);
if (err == nsvErr) {
printf("No such volume\n");
return;
}
err = UnmountVol(0, paramBlock.volumeParam.ioVRefNum);
switch (err) {
case noErr: printf("Okay\n"); break;
case fBsyErr: printf("One or more files are open\n"); break;
default: printf("Failed %d\n", err);
}
}

View File

@ -0,0 +1,2 @@
void mac_list_volumes();
void mac_unmount(int id);

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

View File

@ -0,0 +1,50 @@
#include "mac_scsi.h"
#include "iomega_cmds.h"
// Iomega commands
OSErr iomega_spin_up_cartridge( int id ) {
// issue an Asynchronous START command to induce spinup
char cmd[6] = {
SCSI_Cmd_StartStopUnit,
1, // set the IMMED bit for offline
0,
0,
1, // start the disk spinning
0
};
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
}
OSErr iomega_spin_down_and_eject( int id ) {
// issue an Asynchronous STOP command to induce spindown and ejection
char cmd[6] = {
SCSI_Cmd_StartStopUnit,
1, // set the IMMED bit for offline
0,
0,
2, // eject a Jaz disk after stopping
0
};
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
}
OSErr iomega_set_prevent_removal( int id, bool lock) {
OSErr err;
char cmd[6] = {
SCSI_Cmd_PreventAllow,
0,
0,
0,
lock ? 1 : 0,
0
};
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
}
OSErr iomega_eject_cartridge( int id ) {
OSErr err;
err = iomega_set_prevent_removal(id, false);
if (err != noErr) return err;
return iomega_spin_down_and_eject(id);
}

View File

@ -0,0 +1,8 @@
#include <scsi.h>
typedef Boolean bool;
OSErr iomega_spin_up_cartridge(int id);
OSErr iomega_spin_down_and_eject(int id);
OSErr iomega_set_prevent_removal(int id, bool lock);
OSErr iomega_eject_cartridge(int id);

View File

@ -0,0 +1,116 @@
#include <scsi.h>
#include "mac_scsi.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define READ_TIMEOUT 300 /* 300 ticks = 5 seconds */
OSErr scsi_reset() {
return SCSIReset();
}
OSErr scsi_cmd(int id, void *cmd, size_t clen, void *buff, size_t siz, size_t cnt, int flags, char *status) {
SCSIInstr TIB[3]; /* Transfer instruction block */
OSErr err;
/* Set up the TIB (used by Macintosh SCSI Manager) */
if( cnt != 0 ) {
/* Transfer cnt continguous blocks of size siz, one at a time. */
/* Use this sort of transfer when doing blind transfers to a */
/* disk drive, in order to force the SCSI to poll the bus */
/* between each block [Inside Macintosh: Devices, 3-22] */
TIB[0].scOpcode = scInc;
TIB[0].scParam1 = (long) buff;
TIB[0].scParam2 = siz;
TIB[1].scOpcode = scLoop;
TIB[1].scParam1 = -10;
TIB[1].scParam2 = cnt;
TIB[2].scOpcode = scStop;
TIB[2].scParam1 = 0;
TIB[2].scParam2 = 0;
} else {
/* Transfer siz bytes in one fell swoop. */
TIB[0].scOpcode = scInc;
TIB[0].scParam1 = (long) buff;
TIB[0].scParam2 = siz;
TIB[1].scOpcode = scStop;
TIB[1].scParam1 = 0;
TIB[1].scParam2 = 0;
}
/* Arbitrate for the bus and select the device. */
err = SCSIGet();
if (err != noErr) {printf("SCSIGet Error: %d\n", err); return err;}
err = SCSISelect(id);
if (err != noErr) {/*printf("SCSISelect Error: %d\n", err);*/ return err;}
/* Send the command to the SCSI device and perform the requested I/O */
err = SCSICmd( (Ptr) cmd, clen );
if (err == noErr) {
switch(flags) {
case SCSI_WRITE | SCSI_BLIND: err = SCSIWBlind( (Ptr) TIB ); break;
case SCSI_READ | SCSI_BLIND: err = SCSIRBlind( (Ptr) TIB ); break;
case SCSI_WRITE: err = SCSIWrite( (Ptr) TIB ); break;
case SCSI_READ: err = SCSIRead( (Ptr) TIB ); break;
default: break;
}
if (err != noErr) {
printf("SCSI Read/Write Error: %d\n", err);
}
} else {
printf("SCSICmd Error: %d", err);
}
/* Complete the transaction and release the bus */
short cstat, cmsg;
OSErr comperr = SCSIComplete( &cstat, &cmsg, READ_TIMEOUT );
if (comperr != noErr) {printf("SCSIComplete Error: %d\n", err); return err;}
if(status) *status = cstat;
return err;
}
OSErr scsi_inquiry(int id, int lun, scsi_inq_reply *reply) {
short err;
unsigned char cmd[6] = { SCSI_Cmd_Inquiry, lun << 5, 0x00, 0x00, 0x05, 0x00 };
memset(reply, 0, sizeof(scsi_inq_reply));
/* First we issue a dummy command to get the additional data field, then */
/* we use that number to issue a second command with the corrected length. */
if( (err = scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ)) != noErr) {
return err;
}
cmd[4] += reply->alen;
return scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ);
}
OSErr scsi_request_sense_data(int id, scsi_sense_reply *reply) {
short err;
unsigned char cmd[6] = { SCSI_Cmd_RequestSense, 0x00, 0x00, 0x00, 0x08, 0x00 };
memset(reply, 0, sizeof(scsi_sense_reply));
/* First we issue a dummy command to get the additional data field, then */
/* we use that number to issue a second command with the corrected length. */
if( (err = scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ)) != noErr) {
return err;
}
cmd[4] += reply->alen;
return scsi_cmd(id, cmd, sizeof(cmd), reply, cmd[4], 0, SCSI_READ);
}
OSErr scsi_get_class(int id, int lun, int &dev ) {
scsi_inq_reply reply;
OSErr err = scsi_inquiry(id, lun, &reply );
dev = reply.inf1 & 0x1F;
return err;
}

View File

@ -0,0 +1,87 @@
#include <stdio.h>
typedef Boolean bool;
enum {
SCSI_Cmd_RequestSense = 0x03,
SCSI_Cmd_FormatUnit = 0x04,
SCSI_Cmd_NonSenseData = 0x06,
SCSI_Cmd_Read = 0x08,
SCSI_Cmd_Write = 0x0a,
SCSI_Cmd_CartProtect = 0x0c,
SCSI_Cmd_Inquiry = 0x12,
SCSI_Cmd_ModeSelect = 0x15,
SCSI_Cmd_ModeSense = 0x1a,
SCSI_Cmd_StartStopUnit = 0x1b,
SCSI_Cmd_SendDiagnostic = 0x1d,
SCSI_Cmd_PreventAllow = 0x1e,
SCSI_Cmd_TranslateLBA = 0x22,
SCSI_Cmd_FormatTest = 0x24,
SCSI_Cmd_ReadMany = 0x28,
SCSI_Cmd_WriteMany = 0x2a,
SCSI_Cmd_Verify = 0x2f,
SCSI_Cmd_ReadDefectData = 0x37,
SCSI_Cmd_ReadLong = 0x3e,
SCSI_Cmd_WriteLong = 0x3f
};
enum {
SCSI_DISK = 0x00,
SCSI_TAPE = 0x01,
SCSI_PRINTER = 0x02,
SCSI_CPU_DEVICE = 0x03,
SCSI_WORM = 0x04,
SCSI_CDROM = 0x05,
SCSI_SCANNER = 0x06,
SCSI_OPTICAL = 0x07,
SCSI_MEDIA_CHANGER = 0x08,
SCSI_COM = 0x09,
SCSI_UNKNOWN = 0x1F
};
typedef struct { /* | 7 6 5 4 3 2 1 0 | */
unsigned char inf1; /* 0 | qualifier | device class | */
unsigned char flg1; /* 1 |RMB| reserved | */
unsigned char vers; /* 2 | ISO | ECMA | ANSI | */
unsigned char inf2; /* 3 |AEN|TIO| rsv | data format | */
unsigned char alen; /* 4 | additional length | */
unsigned char rsv1[2]; /* 5 | reserved | */
unsigned char flg2; /* 7 |rel|W32|W16|Syn|Lnk|Rsv|Que|SRs| */
unsigned char vend[8]; /* 8 | manufacturer | */
unsigned char prod[16]; /* 16 | product | */
unsigned char rvsn[4]; /* 32 | revision | */
unsigned char rsv2[20]; /* 36 | vendor unique | */
unsigned char rsv3[40]; /* 56 | reserved | */
unsigned char rsv4[160]; /* 96 | vendor unique | */
} scsi_inq_reply;
// Reference: https://docs.oracle.com/en/storage/tape-storage/storagetek-sl150-modular-tape-library/slorm/request-sense-03h.html#GUID-9309F2C0-ABF8-470E-AE25-E9535C821B39
typedef struct { /* | 7 6 5 4 3 2 1 0 | */
unsigned char err; /* 0 |OK | error code | */
unsigned char seg; /* 1 | segment number | */
unsigned char key; /* 2 | reserved | sense key | */
unsigned char inf1[4]; /* 3 | information | */
unsigned char alen; /* 7 | additional length | */
unsigned char inf2[4]; /* 8 | command specific information | */
unsigned char asc; /* 12 | additional sense code | */
unsigned char ascq; /* 13 | asc qualifier | */
unsigned char fruc; /* 14 | field replaceable unit code | */
unsigned char flg1; /* 15 |SKV|C/D| Rsv |bpv| bit ptr | */
unsigned char fp[2]; /* 16 | field pointer | */
unsigned char rsv[2]; /* 18 | reserved | */
} scsi_sense_reply;
/* Flags for scsi_cmd */
#define SCSI_READ 0x0001
#define SCSI_WRITE 0x0002
#define SCSI_BLIND 0x0004
OSErr scsi_reset();
OSErr scsi_cmd(int id, void *cmd, size_t clen, void *buff, size_t siz, size_t cnt, int flags, char *status = 0);
OSErr scsi_inquiry(int id, int lun, scsi_inq_reply *buff);
OSErr scsi_request_sense_data(int id, scsi_sense_reply *buff);
OSErr scsi_get_class(int id, int lun, int &dev );

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 410 B

383
mac-cpp-source/tip/tip.cpp Normal file
View File

@ -0,0 +1,383 @@
/*******************************************************************************
* TIP.CPP TROUBLE IN PARADISE 05/22/98 *
******************************************************************************/
#include <limits.h>
#include <string.h>
#include <stdio.h>
#include "tip.h"
// ----------------------- Test Monitor Panel Definitions -------------------
#define SET_RECT(LEFT, TOP, RIGHT, BOTTOM) {TOP, LEFT, BOTTOM, RIGHT}
Rect CS_Stat = SET_RECT(114, 8, 242, 28);
Rect TP_Perc = SET_RECT( 12, 56, 409, 72);
Rect SS_Jaz = SET_RECT( 12, 94, 409, 126);
Rect SS_Sid0 = SET_RECT( 12, 94, 409, 110);
Rect TL_Sect = SET_RECT( 75, 154, 203, 170);
Rect ES_Read = SET_RECT(346, 154, 409, 170);
Rect SE_Rect = SET_RECT(222, 154, 255, 221);
/*******************************************************************************
* WndProc
*
* This is the system's main window procedure
*/
void WndProc(long iMessage, long wParam) {
// -------------------------------------------------------------------------
// WM_PAINT
// -------------------------------------------------------------------------
if (iMessage == WM_PAINT) {
// Draw the Lower Horz Button Divider
SetColor(GRAY_COLOR);
MoveTo(15, 289);
LineTo(446, 289);
SetColor(WHITE_COLOR);
LineTo(446, 290);
LineTo(14, 290);
// Paint the Copyright Notice
SetColor(GRAY_COLOR);
TextOut(15, 298, szCopyright_1);
TextOut(15, 311, szCopyright_2);
}
// -------------------------------------------------------------------------
// WM_COMMAND : a button was pressed
// -------------------------------------------------------------------------
else if (iMessage == WM_COMMAND) {
switch(wParam) {
case IDB_QUIT:
if (TestingPhase < TESTING_STARTUP) {
PostQuitMessage();
}
break;
case IDB_TEST:
switch(CartridgeStatus) {
case DISK_SPUN_DOWN:
SpinUpIomegaCartridge(CurrentDevice);
break;
case DISK_AT_SPEED:
printf("Testing the disk\n");
if(TestingPhase != READY_TO_TEST) {
PrepareToBeginTesting();
}
TestTheDisk();
printf("Test finished\n");
break;
case DISK_TEST_UNDERWAY:
UserInterrupt = 1;
break;
case DISK_Z_TRACK_FAILURE:
case DISK_TEST_FAILURE:
case DISK_PROTECTED:
//EjectIomegaCartridge();
break;
case DISK_LOW_SPARES:
PrepareToBeginTesting();
break;
}
break;
default:
break;
}
}
}
BtnList tipBtns[] = {
{IDB_TEST, szPressToStart, 200, 301, 160, 24, true}, // Added by MLT
{IDB_BACK, szBack, 185-28, 301, 80, 24, false},
{IDB_NEXT, szNext, 264-28, 301, 80, 24, false},
{IDB_QUIT, szQuit, 367+35, 301, 45, 24, true},
{0, 0, 0, 0, 0, 0, 0}
};
/*******************************************************************************
* SUNKEN FIELDS
*******************************************************************************/
void SunkenFields(Rect *pFirstRect, long count, long yspacing) {
Rect drawRect;
drawRect = *pFirstRect; // make a local copy
do {
DrawEdge(&drawRect, BDR_SUNKENOUTER, BF_RECT);
drawRect.top += yspacing;
drawRect.bottom += yspacing;
} while(--count);
}
/*******************************************************************************
* PAINT TEXT ARRAY
*******************************************************************************/
void PaintTextArray(TextList *list, long color) {
SetColor(color);
for(int i = 0; list[i].str; i++) {
TextOut(list[i].x, list[i].y, list[i].str);
}
}
/*******************************************************************************
* PAINT TEST PHASE
*******************************************************************************/
void PaintTestPhase() {
DrawLed(320, 5, TestingPhase == READING_DATA ? GREEN_COLOR : BACK_COLOR);
DrawLed(336, 5, TestingPhase == WRITING_PATT ? RED_COLOR : BACK_COLOR);
DrawLed(336, 21, TestingPhase == READING_PATT ? GREEN_COLOR : BACK_COLOR);
DrawLed(320, 21, TestingPhase == WRITING_DATA ? RED_COLOR : BACK_COLOR);
}
/*******************************************************************************
* PAINT CART STATUS
*
* Paints the textual cartridge status window
*******************************************************************************/
void PaintCartStatus() {
// blank out any previous status display
SetColor(BACK_COLOR);
Rectangle(115, 9, 241, 27);
// display the new cartridge status
long eax = CartridgeStatus - 1;
if(eax < 0 || eax >= LAST_CART_STATUS) {
eax = 0;
}
// pickup the pointer to the string
const char *esi;
//if (DriveCount) {
esi = CartStatStrings[eax];
//} else {
// esi = szNoIomegaDrives;
//}
SetColor(BLACK_COLOR);
TextOutCentered(115, 9, 241 - 115, 27 - 9, esi);
}
/*******************************************************************************
* PAINT BAR GRAPH
*******************************************************************************/
void PaintBarGraph(int Xleft, int Ytop, int XWidth, int YHeight, long BarColor, long BarValue, char *pRightText, bool Active) {
// fill the entire rectangle with background gray
SetColor(BACK_COLOR);
Rectangle(Xleft, Ytop, Xleft + XWidth, Ytop + YHeight);
if (Active) { // now fleshout the bar ONLY IF we're active
// if RightText string is non-null, paint it in darker gray
if(pRightText) {
SetColor(GRAY_COLOR);
TextOutCentered(Xleft, Ytop, XWidth, YHeight, pRightText);
}
// now paint the active portion
const long AbsoluteBarWidth = XWidth * BarValue / 100;
SetColor(BarColor, BLACK_COLOR);
Rectangle(Xleft, Ytop, Xleft + AbsoluteBarWidth, Ytop + YHeight);
// now place the floating percentage into the middle (if it fits there)
if(BarValue) {
char PercentString[8];
sprintf(PercentString, szBarChartPercent, BarValue);
SetColor(WHITE_COLOR);
TextOutCentered(Xleft, Ytop, AbsoluteBarWidth, YHeight, PercentString);
}
}
}
/*******************************************************************************
* PAINT THE BAR GRAPHS
*
* This paints the two or three bar graphs on the test monitor window.
*******************************************************************************/
void PaintTheBarGraphs(bool Active) {
long ebx, ecx;
PaintBarGraph(13, 57, 395, 14, BLUE_COLOR, PercentComplete, NULL, Active);
if(JazDrive) {
ebx = Side_0_SparesCount;
ecx = MAXIMUM_JAZ_SPARES;
if(ebx > ecx) { // if Spares > MAXIMUM
ebx = ecx; // clip Spares down to MAX
}
PaintBarGraph(13, 95, 395, 30, RED_COLOR, ebx*100/ecx, NULL, Active);
} else {
ebx = Side_0_SparesCount;
ecx = MAXIMUM_ZIP_SPARES;
PaintBarGraph(13, 95, 395, 14, RED_COLOR, ebx*100/ecx, "Side 0", Active);
ebx = Side_1_SparesCount;
ecx = MAXIMUM_ZIP_SPARES;
PaintBarGraph(13, 111, 395, 14, RED_COLOR, ebx*100/ecx, "Side 1", Active);
}
}
/*******************************************************************************
* PAINT CENTERED STRING
*
* Paubts a string int a rectangular region
*******************************************************************************/
void PaintCenteredString(int Xleft, int Ytop, int XWidth, int YHeight, const char *pText, bool Active) {
// fill the entire rectangle with background gray
SetColor(BACK_COLOR);
Rectangle(Xleft, Ytop, Xleft + XWidth, Ytop + YHeight);
// now fleshout the bitmap ONLY IF we're active
if(Active) {
SetColor(BLACK_COLOR);
TextOutCentered(Xleft, Ytop, XWidth, YHeight, pText);
}
}
/*******************************************************************************
* PAINT CENTERED VALUE
*
* Paints a decimal-value into a rectangular region
*******************************************************************************/
void PaintCenteredValue(int Xleft, int Ytop, int XWidth, int YHeight, long value, bool Active) {
char szString[40];
// convert our value into a string
sprintf(szString, szCenteredDecimal, value);
// and paint it's value
PaintCenteredString(Xleft, Ytop, XWidth, YHeight, szString, Active);
}
/*******************************************************************************
* PAINT TEST STATISTICS
*
* This paints the two columns of testing statistics on the test minitor window.
*******************************************************************************/
void PaintTestStatistics(bool Active) {
char szString[40];
// assemble and paint the sector testing range
long eax = SingleTransferLBA;
if (eax) {
sprintf(szString, szCenteredDecimal, eax);
} else {
eax = FirstLBASector;
if (!TestingPhase) {
eax = 0;
}
sprintf(szString, szCenteredDecimal, eax);
strcat(szString, szSpaceDashSpace);
eax = FirstLBASector + NumberOfLBAs;
if (TestingPhase == READY_TO_TEST) {
eax = LastLBAOnCartridge;
}
sprintf(szString + strlen(szString), szCenteredDecimal, eax);
}
PaintCenteredString(76, 155, 126, 14, szString, Active);
// show the LastError
char *errStr = 0;
for (int i = 0; errorTypeList[i].str; i++) {
errStr = errorTypeList[i].str;
if (errorTypeList[i].code == LastError) break;
}
PaintCenteredString(76, 172, 126, 14, errStr, Active);
// show the elapsed time
CvrtSecondsToHMSstring(szString, SecondsElapsed);
PaintCenteredString(76, 189, 126, 14, szString, Active);
// see if it's time for us to estimate...
if(SecondsElapsed - ElapsedTimeOfLastEstimate > 15 && PercentComplete > 0) {
// assemble the remaining time
ElapsedTimeOfLastEstimate = SecondsElapsed;
CurrentTotalTimeEstimate = SecondsElapsed * 100 / PercentComplete;
}
// given the current estimate time, show the remaining time!
eax = CurrentTotalTimeEstimate;
if(eax) {
eax -= SecondsElapsed;
if(eax < 0) eax = 0;
CvrtSecondsToHMSstring(szString, eax);
} else {
strcpy(szString, szEstimating);
}
PaintCenteredString(76, 206, 126, 14, szString, Active);
// now show the error accumulations...
long TotalErrors = SoftErrors + FirmErrors + HardErrors;
PaintCenteredValue(347, 155, 61, 14, SoftErrors, Active);
PaintCenteredValue(347, 172, 61, 14, FirmErrors, Active);
PaintCenteredValue(347, 189, 61, 14, HardErrors, Active);
PaintCenteredValue(347, 206, 61, 14, TotalErrors, Active);
}
void CvrtSecondsToHMSstring(char *szString, long seconds) {
const long h = (seconds / 3600);
const long m = (seconds / 60) % 60;
const long s = (seconds % 60);
sprintf(szString, szHoursMinsSecs, h, m, s);
}
/*******************************************************************************
* TEST MONITOR WND PROC
*******************************************************************************/
void TestMonitorWndProc() {
long eax;
SetColor(BLACK_COLOR);
TextOut(12, 9, szCartStatus);
DrawEdge(&CS_Stat, BDR_SUNKENOUTER, BF_RECT);
PaintCartStatus();
// draw the sunken rectangles
DrawEdge(&TP_Perc, BDR_SUNKENOUTER, BF_RECT);
DrawEdge(&SE_Rect, BDR_SUNKENOUTER, BF_RECT);
SunkenFields(&TL_Sect, 4, 17);
SunkenFields(&ES_Read, 4, 17);
if(JazDrive) { // draw a single LARGE rectangle
DrawEdge(&SS_Jaz, BDR_SUNKENOUTER, BF_RECT);
} else { // draw a pair of smaller rectangles
SunkenFields(&SS_Sid0, 2, 16);
}
if((CartridgeStatus == DISK_AT_SPEED) || (CartridgeStatus == DISK_SPUN_DOWN) || (CartridgeStatus >= DISK_LOW_SPARES)) {
PaintTheBarGraphs(true);
PaintTestStatistics(true);
eax = BLACK_COLOR;
} else {
PaintTheBarGraphs(false);
PaintTestStatistics(false);
eax = GRAY_COLOR;
}
PaintTextArray(TestBlackText, eax);
PaintTextArray(TestGrayText, GRAY_COLOR);
PaintTestPhase();
// TODO: paint the little speaker icon
}
/*******************************************************************************
* UPDATE RUN TIME DISPLAY
*******************************************************************************/
void UpdateRunTimeDisplay() {
GetDC(hTestMonitor);
PaintTestPhase();
PaintTheBarGraphs(true);
PaintTestStatistics(true);
PaintCartStatus();// Added by MLT
ReleaseDC(hTestMonitor);
}
/*******************************************************************************
* UPDATE CURRENT SECTOR
*******************************************************************************/
void UpdateCurrentSector() {
GetDC(hTestMonitor);
char szString[40];
sprintf(szString, szCenteredDecimal, SingleTransferLBA);
PaintCenteredString(76, 155, 126, 14, szString, true);
ReleaseDC(hTestMonitor);
}
/*******************************************************************************
* UPDATE RUN PHASE DISPLAY
*******************************************************************************/
void UpdateRunPhaseDisplay() {
GetDC(hTestMonitor);
PaintTestPhase();
ReleaseDC(hTestMonitor);
}
/*******************************************************************************
* ERROR SOUND
*******************************************************************************/
void ErrorSound() {
}

212
mac-cpp-source/tip/tip.h Normal file
View File

@ -0,0 +1,212 @@
typedef Boolean bool;
extern WindowPtr tipWindow;
void run_tip();
#define MINIMUM_JAZ_SPARES 500
#define MAXIMUM_JAZ_SPARES 2557
#define MINIMUM_ZIP_SPARES 50
#define MAXIMUM_ZIP_SPARES 126
extern long CurrentDevice;
extern bool JazDrive; // true if the current drive
extern long CartridgeStatus;
extern long LastLBAOnCartridge;
extern unsigned long StartingInstant;
extern long NumberOfLBAs;
extern long Side_0_SparesCount; // JAZ has only one count
extern long Side_1_SparesCount; // ZIP has counts for both sides
extern long Initial_Side_0_Spares;
extern long Initial_Side_1_Spares;
extern long TestingPhase; // 0 = not testing, no data ...
extern long PercentComplete;
extern long FirstLBASector;
extern long NumberOfLBAs;
extern long SecondsElapsed;
extern long SoftErrors;
extern long FirmErrors;
extern long HardErrors;
extern long ElapsedTimeOfLastEstimate;
extern long CurrentTotalTimeEstimate;
extern bool UserInterrupt;
extern long LastError;
extern long SingleTransferLBA;
// ----------------------- Macintosh Compatibility -----------------------
enum {
BACK_COLOR = -1,
BLACK_COLOR = 0x000000,
LTGRAY_COLOR = 0xc0c0c0,
GRAY_COLOR = 0x808080,
WHITE_COLOR = 0xffffff,
BLUE_COLOR = 0x0000ff,
RED_COLOR = 0xff0000,
GREEN_COLOR = 0x00ff00,
};
#define BDR_SUNKENOUTER 1
#define BF_RECT 1
#define WM_PAINT 1
#define WM_COMMAND 2
void SetColor(long color);
void SetColor(long color, long monoColor);
void DrawLed(int x, int y, long color);
void StrToPascal(Str255 pStr, const char *str);
long GetTextExtent(const char *str, unsigned long len);
void TextOut(int x, int y, Str255 str);
void TextOut(int x, int y, const char *str);
void TextOutCentered(int x, int y, int w, int h, const char *str);
void SetButtonText(const char *str);
void Rectangle(int left, int top, int right, int bottom);
void DrawEdge(Rect *qrc, int edge, int grfFlags);
void PostQuitMessage();
unsigned long GetSystemTime();
#define hTestMonitor -20, -10
#define hMainWnd 0, 40
#define GetDC(h) {GrafPtr oldPort; \
GetPort(&oldPort); \
SetPort(tipWindow); \
SetOrigin(h);
#define ReleaseDC(h) SetOrigin(0,0); \
SetPort(oldPort);}
// ------------------------------ Cartridge Status -------------------------------
enum {
DISK_STATUS_UNKNOWN = 1,
DISK_AT_SPEED = 2,
DISK_SPINNING_UP = 3,
DISK_NOT_PRESENT = 4,
DISK_SPUN_DOWN = 5,
DISK_STALLED = 6,
DISK_Z_TRACK_FAILURE = 7,
DISK_PROTECTED = 8,
DISK_LOW_SPARES = 9,
DISK_TEST_UNDERWAY = 10,
DISK_TEST_FAILURE = 11,
LAST_CART_STATUS = 11
};
// ---------------------------- Testing Phase Status -----------------------------
enum {
UNTESTED = 0,
READY_TO_TEST = 1,
TESTING_STARTUP = 2,
READING_DATA = 3,
WRITING_PATT = 4,
READING_PATT = 5,
WRITING_DATA = 6
};
/*******************************************************************************
* STRINGS
*******************************************************************************/
extern const char *szWindowTitle;
extern const char *szCopyright_1;
extern const char *szCopyright_2;
extern const char *szSide0;
extern const char *szSide1;
extern const char *szSpaceDashSpace;
extern const char *szBarChartPercent;
extern const char *szCenteredDecimal;
extern const char *szCenteredHex;
extern const char *szHoursMinsSecs;
extern const char *szCartStatus;
extern const char *szEstimating;
extern const char *szOneMoment;
extern const char *szPressToStart;
extern const char *szPressToStop;
extern const char *szPressToSpin;
extern const char *szPressToEject;
extern const char *szPressToProceed;
/************* Cartridge Status Text *************/
typedef struct {long code; char *str;} ErrorTypeList;
typedef struct {int x, y; char *str;} TextList;
extern const char *szUnknownStat;
extern const char *szAtSpeedStat;
extern const char *szSpinningUp;
extern const char *szNotPresent;
extern const char *szSpunDown;
extern const char *szStalledStat;
extern const char *szZtrackFailure;
extern const char *szDiskLocked;
extern const char *szLowSpares;
extern const char *szTestUnderway;
extern const char *DriveUnderTest;
extern const char *szTestFailure;
extern const char *szNoIomegaDrives;
extern const char *CartStatStrings[];
extern ErrorTypeList errorTypeList[];
extern TextList TestBlackText[];
extern TextList TestGrayText[];
/************* Window Creation Data **************/
extern const char *szBack;
extern const char *szNext;
extern const char *szQuit;
#define IDB_BACK 0xFF00
#define IDB_NEXT 0xFF01
#define IDB_QUIT 0xFF02
#define IDB_TEST 0xFF03
typedef struct {long id; const char *name; int x; int y; int w; int h; bool visible;} BtnList;
extern BtnList tipBtns[];
/*******************************************************************************
* FUNCTION PROTOTYPES
*******************************************************************************/
void PaintCenteredString(int Xleft, int Ytop, int XWidth, int YHeight, const char *pText, bool Active);
void PaintCenteredValue(int Xleft, int Ytop, int XWidth, int YHeight, long value, bool Active);
void SunkenFields(Rect *pFirstRect, long count, long yspacing);
void PaintCartStatus();
void PaintTextArray(TextList *list, long color);
void PaintBarGraph(int Xleft, int Ytop, int XWidth, int YHeight, long BarColor, long BarValue, char *pRightText, bool Active);
void PaintTestPhase();
void PaintTheBarGraphs(bool Active);
void PaintTestStatistics(bool Active);
void CvrtSecondsToHMSstring(char *szString, long seconds);
void UpdateCurrentSector();
void UpdateRunTimeDisplay();
void UpdateRunPhaseDisplay();
void ErrorSound();
void ProcessPendingMessages();
void WndProc(long iMessage, long wParam);
void TestMonitorWndProc();
void TestButtonClicked();
void GetCommandDetails(char command, char &cmd_flags, char &cmd_length);
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen);
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen);
long SetModePage(short Device, void *pBuffer);
void ModifyModePage(char *PageBuff, char eec, char retries);
void SetErrorRecovery(bool Retries, bool ECC, bool Testing);
long GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen);
long LockCurrentDrive();
long UnlockCurrentDrive();
long SpinUpIomegaCartridge(short Device);
void GetSpareSectorCounts(bool);
long PerformRegionTransfer(short XferCmd, void *pBuffer);
long TestTheDisk();
long GetElapsedTimeInSeconds();
void PrepareToBeginTesting();
void BumpErrorCounts(long ErrorCode);

View File

@ -0,0 +1,684 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "mac_scsi.h"
#include "tip.h"
//#define DEMO
#define BYTE_AT(a) *((char*)&(a))
#define WORD_AT(a) *((short*)&(a))
#define DWORD_AT(a) *((long*)&(a))
#define MAKE_LITTLE_ENDIAN(a) a // Don't do anything on 68000
#define MAKE_BIG_ENDIAN(a) a // Don't do anything on 68000
// offsets to the various sector data images
#define ZIP_100_PART 0x0000
#define ZIP_100_BOOT 0x0200
#define ZIP_250_PART 0x0400
#define ZIP_250_BOOT 0x0600
#define JAZ_1GB_PART 0x0800
#define JAZ_1GB_BOOT 0x0A00
#define JAZ_2GB_PART 0x0C00
#define JAZ_2GB_BOOT 0x0E00
struct DEFECT_LIST_HEADER {
char DLH_reserved; // (00h)
char DLH_BitFlags; // [000] [P] [G] [xxx - defect list format]
char DLH_DefectListLength;
};
//-------------------------- Drive Array Status Flags ---------------------------
#define JAZ_DRIVE 0x00010000
#define MEDIA_CHANGED 0x00020000
#define DISK_EJECTING 0x00040000 // we've asked for eject and waiting ...
#define ODD_BYTE_COMPENSATION 0x00080000 // special handling for ODD length PSWD
#define MAX_DRIVE_COUNT 16 // we can handle up to 16 Zip/Jaz drives
#define ERROR_RECOVERY_PAGE 1 // From disassembly
#define FORMAT_STATUS_PAGE 1
#define DISK_STATUS_PAGE 2
#define NEW_DISK_STATUS_OFFSET 3 // newer offset of the Disk Status Byte
#define OLD_DISK_STATUS_OFFSET 1 // older offset of the Disk Status Byte
#define JAZ_SPARES_COUNT_OFFSET 68 // offsets into DiskStat tbl
#define NEW_ZIP_SIDE_0_SPARES_COUNT_OFFSET 13
#define NEW_ZIP_SIDE_1_SPARES_COUNT_OFFSET 17
#define OLD_ZIP_SIDE_0_SPARES_COUNT_OFFSET 11
#define OLD_ZIP_SIDE_1_SPARES_COUNT_OFFSET 15
#define JAZ_PROTECT_MODE_OFFSET 21
#define NEW_ZIP_PROTECT_MODE_OFFSET 21
#define OLD_ZIP_PROTECT_MODE_OFFSET 19
#define JAZ_LAST_LBA_OFFSET 5
#define NEW_ZIP_LAST_LBA_OFFSET 5
#define OLD_ZIP_LAST_LBA_OFFSET 3
#define DRIVE_A_SUPPORT_BIAS 32 // reduce total by 32 for DRIVE A support
#define BYTES_PER_SECTOR 512
#define MAX_SECTORS_PER_TEST 20
#define BADNESS_THRESHOLD 10
#define SS_ERR 0x00000004 // From disassembly
#define BUFFER_TOO_BIG 0x00FFFFE6 // From disassembly
#define LBA_TOO_LARGE 0x00210005 // From disassembly
#define INCOMPATIBLE_MEDIA 0x00300002 // From disassembly
#define MEDIA_NOT_PRESENT 0x003a0002 // From disassembly
#define DEFECT_LIST_READ_ERROR 0x001c0003 // From disassembly
#define CHECK_CONDITION 0x02
enum {
szBadResult,
szInterrupted,
szExplainResult,
szPerfectResult
};
long CurrentDevice = 0;
bool JazDrive; // true if the current drive
long CartridgeStatus = /*DISK_NOT_PRESENT*/ DISK_AT_SPEED;
unsigned long StartingInstant;
// ----------------------------- Run Time Variables ------------------------------
long Side_0_SparesCount; // JAZ has only one count
long Side_1_SparesCount; // ZIP has counts for both sides
long Initial_Side_0_Spares;
long Initial_Side_1_Spares;
long TestingPhase; // 0 = not testing, no data ...
long PercentComplete;
long FirstLBASector;
long NumberOfLBAs;
long LastLBAOnCartridge;
long SecondsElapsed;
long SoftErrors;
long FirmErrors;
long HardErrors;
long ElapsedTimeOfLastEstimate;
long CurrentTotalTimeEstimate;
bool UserInterrupt;
long LastError;
long SingleTransferLBA;
/*******************************************************************************
* GET COMMAND DETAILS
*
* Given a SCSI command byte, this returns the command
* block length in AL and the Command Flags in AH
*******************************************************************************/
#define TEN_BYTE_CMDS 0x1F
#define SRB_DIR_IN SCSI_READ
#define SRB_DIR_OUT SCSI_WRITE
void GetCommandDetails(char command, char &cmd_flags, char &cmd_length) {
char CommandDetailsTable[] = {
SCSI_Cmd_RequestSense, SRB_DIR_IN, // 03 IN == get from drive
SCSI_Cmd_FormatUnit, 0, // 04 OUT == send to drive
SCSI_Cmd_NonSenseData, SRB_DIR_IN, // 06
SCSI_Cmd_Read, SRB_DIR_IN, // 08
SCSI_Cmd_Write, SRB_DIR_OUT, // 0A
SCSI_Cmd_CartProtect, SRB_DIR_OUT, // 0C
SCSI_Cmd_Inquiry, SRB_DIR_IN, // 12
SCSI_Cmd_ModeSelect, SRB_DIR_OUT, // 15
SCSI_Cmd_ModeSense, SRB_DIR_IN, // 1A
SCSI_Cmd_StartStopUnit, 0, // 1B
SCSI_Cmd_SendDiagnostic, 0, // 1D
SCSI_Cmd_PreventAllow, 0, // 1E
SCSI_Cmd_TranslateLBA, SRB_DIR_IN, // 22
SCSI_Cmd_FormatTest, 0, // 24
SCSI_Cmd_ReadMany, SRB_DIR_IN, // 28
SCSI_Cmd_WriteMany, SRB_DIR_OUT, // 2A
SCSI_Cmd_Verify, 0, // 2F
SCSI_Cmd_ReadDefectData, SRB_DIR_IN, // 37
SCSI_Cmd_ReadLong, SRB_DIR_IN, // 3E
SCSI_Cmd_WriteLong, SRB_DIR_OUT // 3F
};
cmd_flags = 0; // ; if we don't locate it ... return ZERO
// search the table for the command entry
for(int i = 0; i < sizeof(CommandDetailsTable); i += 2) {
if(CommandDetailsTable[i] == command) { // if we match we're done
cmd_flags = CommandDetailsTable[i+1];
break;
}
}
cmd_length = 6; // presume a short (6 byte) command
if(command > TEN_BYTE_CMDS) // but if it's a LONG one ....
cmd_length = 10;
}
/*******************************************************************************
* SCSI COMMAND
*
* This executes a SCSI command through the interface. It receives a
* pointer to a standard SCSI command block (SCB) and a pointer and
* length to an IoBuffer for the command. It returns the complete
* three-byte sense code from the command.
*******************************************************************************/
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen) {
char cmd_length, cmd_flags, cmd_status;
GetCommandDetails(lpCmdBlk[0], cmd_flags, cmd_length);
// call the SCSI interface to forward the command to the device
OSErr err = scsi_cmd(Device, lpCmdBlk, cmd_length, lpIoBuf, IoBufLen, 0, cmd_flags, &cmd_status);
if(err != noErr) {
return SS_ERR;
}
if(cmd_status == 0) {
printf("SCSI OK\n");
// if the command did not generate any Sense Data, just return NULL
return 0;
}
else if(cmd_status == 2) { // Check Condition
printf("SCSI CHK CONDITION\n");
// Request sense data
scsi_sense_reply sense_data;
scsi_request_sense_data(Device, &sense_data);
// okay, we have an SS_ERR condition, let's check the SENSE DATA
// assemble [00 ASC ASCQ SenseKey]
return (sense_data.asc << 16) ||
(sense_data.ascq << 8) ||
sense_data.key;
}
else {
// else, if it's *NOT* a "Sense Data" error (SS_ERR)
return cmd_status | 0x00FFFF00; // [00 FF FF er]
}
}
/*******************************************************************************
* GET MODE PAGE
*******************************************************************************/
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen) {
char Scsi[6] = {0};
Scsi[0] = SCSI_Cmd_ModeSense;
Scsi[2] = PageToGet;
Scsi[4] = BufLen;
return SCSICommand(Device, Scsi, pBuffer, BufLen);
}
/*******************************************************************************
* SET MODE PAGE
*******************************************************************************/
long SetModePage(short Device, void *pBuffer) {
char Scsi[6] = {0}; // init the SCSI parameter block
char* ebx = (char*) pBuffer; // get a pointer to the top of buffer
char ecx = ebx[0] + 1; // adjust it up by one
Scsi[0] = SCSI_Cmd_ModeSelect; // set the command
Scsi[1] = 0x10; // set the Page Format bit
Scsi[4] = ecx; // set the parameter list length
return SCSICommand(Device, Scsi, pBuffer, ecx);
}
/*******************************************************************************
* SET ERROR RECOVERY
*******************************************************************************/
void ModifyModePage(char *PageBuff, char ecc, char retries) {
long eax = PageBuff[3]; // get the Block Descriptor Length
char *ebx = PageBuff + 4; // get just past the header address
// form ebx == the offset to the top of the page we've read ...
ebx += eax;
ebx[0] &= ~0x80; // always turn off the PS bit (parameters savable)
ebx[2] = 0xC0 | ecc; // set the ECC fields
ebx[3] = retries; // set the common retry count
if(ebx[1] > 6) // if we have a large format page...
ebx[8] = retries; // then set the write count too
}
void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
char PageBuff[40];
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
#define EARLY_RECOVERY 0x08
#define PER 0x04
#define SUPPRESS_ECC 0x01
// set the ECC fields
char ecc = SUPPRESS_ECC; // presume ECC suppression
if(ECC) {
ecc = EARLY_RECOVERY; // enable ECC and Early Recovery
if(Testing) {
ecc = EARLY_RECOVERY | PER; // we're testing, so EER & PER
}
}
// set the retry counts
char retries = 0x16; // set retries to 22 for Zip drive
if(JazDrive)
retries = 0x64; // and to 100 for Jaz drive
if(!Retries) // But if we have no retries ...
retries = 0;
ModifyModePage(PageBuff, ecc, retries);
long eax = SetModePage(CurrentDevice, PageBuff);
// if we had an invalid field in the CDB (the EER bit was on)
if (eax == 0x00260005) {
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
ecc &= ~0x08; // same, *BUT*NOT* Early Recovery
ModifyModePage(PageBuff, ecc, retries);
SetModePage(CurrentDevice, PageBuff);
}
}
/*******************************************************************************
* GET NON-SENSE PAGE DATA
*
* Given Adapter, Device, DataPage, and a Buffer to receive the data, this
* fills the buffer we're given and returns with the SCSI Completion Code
*******************************************************************************/
long GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen) {
char Scsi[6] = {0};
Scsi[0] = SCSI_Cmd_NonSenseData; // do a Non-Sense Data Read
Scsi[2] = DataPage; // which page to read
Scsi[4] = BufLen; // tell drive page is this long
return SCSICommand(Device, Scsi, Buffer, BufLen);
}
/*******************************************************************************
* LOCK CURRENT DRIVE
*******************************************************************************/
long LockCurrentDrive() {
char Scsi[6] = {0};
Scsi[0] = SCSI_Cmd_PreventAllow;
Scsi[4] = 1; // set to ONE to lock the drive
return SCSICommand(CurrentDevice, Scsi, NULL, 0);
}
/*******************************************************************************
* UNLOCK CURRENT DRIVE
*******************************************************************************/
long UnlockCurrentDrive() {
char Scsi[6] = {0};
Scsi[0] = SCSI_Cmd_PreventAllow;
return SCSICommand(CurrentDevice, Scsi, NULL, 0);
}
/*******************************************************************************
* SPIN UP IOMEGA CARTRIDGE
*******************************************************************************/
long SpinUpIomegaCartridge(short Device) {
char Scsi[6] = {0};
Scsi[0] = SCSI_Cmd_StartStopUnit;
Scsi[1] = 1; // set the IMMED bit for offline
Scsi[4] = 1; // start the disk spinning
return SCSICommand(Device, Scsi, NULL, 0);
}
/*******************************************************************************
* GET SPARE SECTOR COUNTS
*
* This returns NON-ZERO if we have trouble and posted the error message
* into the RichText control, else it sets the number of spares available
*******************************************************************************/
void GetSpareSectorCounts(bool) {
DEFECT_LIST_HEADER DefectHeader;
long eax = 0, ebx, edx;
short ch, cl;
ListChk:
// ask for the defect list to make sure we're able to read it
char Scsi[10] = {0};
Scsi[0] = SCSI_Cmd_ReadDefectData;
Scsi[2] = 0x1e; // 0b00011110 defect format, G/P bits
Scsi[8] = 4; // ask for only FOUR bytes
eax = SCSICommand(CurrentDevice, Scsi, &DefectHeader, sizeof(DefectHeader));
if ((!eax) || (eax == INCOMPATIBLE_MEDIA)) {
// we could read its defect list ... so show it!
// --------------------------------------------------------------------------
// MLT: looks like on the Iomega Zip 100, the maximum size for DiskStat is 63
// rather than 72; it looks like this code is causing a SCSI transfer error
// here... might be better to conditionally check for Jaz drive
char DiskStat[72];
eax = GetNonSenseData(CurrentDevice, DISK_STATUS_PAGE, DiskStat, sizeof(DiskStat));
if (!eax) /*goto ListChk;*/ return;
// --------------------------------------------------------------------------
ch = 0; // clear the DRIVE_A_SUPPORT
if (JazDrive) {
eax = WORD_AT(DiskStat[JAZ_SPARES_COUNT_OFFSET]);
ebx = 0;
cl = BYTE_AT(DiskStat[JAZ_PROTECT_MODE_OFFSET]);
edx = DWORD_AT(DiskStat[JAZ_LAST_LBA_OFFSET]);
} else {
if (DiskStat[0] == DISK_STATUS_PAGE) {
eax = WORD_AT(DiskStat[NEW_ZIP_SIDE_0_SPARES_COUNT_OFFSET]);
ebx = WORD_AT(DiskStat[NEW_ZIP_SIDE_1_SPARES_COUNT_OFFSET]);
cl = BYTE_AT(DiskStat[NEW_ZIP_PROTECT_MODE_OFFSET]);
edx = DWORD_AT(DiskStat[NEW_ZIP_LAST_LBA_OFFSET]);
ch--; // set the DRIVE_A_SUPPORT
}
else {
eax = WORD_AT(DiskStat[OLD_ZIP_SIDE_0_SPARES_COUNT_OFFSET]);
ebx = WORD_AT(DiskStat[OLD_ZIP_SIDE_1_SPARES_COUNT_OFFSET]);
cl = BYTE_AT(DiskStat[OLD_ZIP_PROTECT_MODE_OFFSET]);
edx = DWORD_AT(DiskStat[OLD_ZIP_LAST_LBA_OFFSET]);
}
if(ebx == 0) {
CartridgeStatus = DISK_TEST_FAILURE;
return;
}
}
//---------------------------
// bswap edx; save the last LBA in any event
//---------------------------
if(ch) {
edx -= DRIVE_A_SUPPORT_BIAS;
}
LastLBAOnCartridge = edx;
MAKE_LITTLE_ENDIAN(eax); // make it little endian
Side_0_SparesCount = eax;
MAKE_LITTLE_ENDIAN(ebx); // make it little endian
Side_1_SparesCount = ebx;
// compute the number of troubles we encountered during the testing
FirmErrors = Initial_Side_0_Spares - Side_0_SparesCount;
FirmErrors += Initial_Side_1_Spares - Side_1_SparesCount;
// check to see whether we have ANY spare sectors remaining
if(!Side_0_SparesCount && !Side_1_SparesCount) {
CartridgeStatus = DISK_TEST_FAILURE;
return;
}
// MLT: The code for removing the ZIP protection has been omitted
return; // return zero since no error
}
else {
// trouble of some sort ... so suppress controls and
// show the richedit control for the trouble
if (eax == DEFECT_LIST_READ_ERROR) {
CartridgeStatus = DISK_Z_TRACK_FAILURE;
return;
}
else if (eax == MEDIA_NOT_PRESENT) {
CartridgeStatus = MEDIA_NOT_PRESENT;
}
}
}
/*******************************************************************************
* GET ELAPSED TIME IN SECONDS
*******************************************************************************/
long GetElapsedTimeInSeconds() {
return GetSystemTime() - StartingInstant;
}
/*******************************************************************************
* PREPARE TO BEGIN TESTING
*******************************************************************************/
void PrepareToBeginTesting() {
// Zero all of the testing variables
TestingPhase = 0; // 0 = not testing, no data ...
PercentComplete = 0;
FirstLBASector = 0;
NumberOfLBAs = 0;
SoftErrors = 0;
FirmErrors = 0;
HardErrors = 0;
UserInterrupt = 0;
LastError = 0;
#ifdef DEMO
LastLBAOnCartridge = 99999;
SoftErrors = 6;
FirmErrors = 2;
HardErrors = 1;
UserInterrupt = 0;
LastError = 0x0C8001;
Side_0_SparesCount = 12;
Side_1_SparesCount = 20;
#endif
}
/*******************************************************************************
* BUMP ERROR COUNTS
*
* See: https://en.wikipedia.org/wiki/Key_Code_Qualifier
*******************************************************************************/
void BumpErrorCounts(long ErrorCode) {
long eax = ErrorCode;
if (eax == BUFFER_TOO_BIG) { // if we got BUFFER TOO BIG, halt!
UserInterrupt = 1;
}
long ebx = eax & 0x00FF00FF; // mask off the middle byte
if (ebx == 0x00150004) // if it was one of the many seek
eax = ebx; // errors, cvrt to seek error
if (eax)
LastError = eax;
if (eax == 0x320003 || eax == 0x328F03)
CartridgeStatus = DISK_LOW_SPARES;
if (eax & 0xFF == 1) // recovered error
SoftErrors++;
else
HardErrors++;
}
/*******************************************************************************
* PERFORM REGION TRANSFER
*******************************************************************************/
long PerformRegionTransfer(short XferCmd, void *pBuffer) {
return -1;
char Scsi[10] = {0}; // clear out the SCSI CDB
const long InitialHardErrors = HardErrors;
SetErrorRecovery(false, false, true); // disable Retries & ECC
Scsi[0] = XferCmd;
DWORD_AT(Scsi[2]) = MAKE_BIG_ENDIAN(FirstLBASector); // WHICH LBA's to read, BIG endian
WORD_AT(Scsi[7]) = MAKE_BIG_ENDIAN(NumberOfLBAs); // HOW MANY to read, BIG endian
long eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
return 1;
// if we failed somewhere during our transfer ... let's zero in on it
if (eax) {
if ( eax == SS_ERR || // if it's a CONTROLLER ERROR, skip!
eax == BUFFER_TOO_BIG ||
eax == LBA_TOO_LARGE) {
goto Exit;
}
//--------------------------------------------------------------------------
// Save error and current Soft + Hard Error count to see if we do FIND the glitch ...
const long GlitchError = eax; // save the error which stopped us!
const long GlitchCount = SoftErrors + HardErrors;
char *LocalBuffer = (char*) pBuffer;
ErrorSound();
SingleTransferLBA = FirstLBASector;
// Perform transfer LBA block at a time
for(long i = 0; i < NumberOfLBAs; ++i) {
UpdateCurrentSector();
// setup for our series of transfer tests ...
// disable all recovery techniques
SetErrorRecovery(false, false, true); // disable Retries & ECC
memset(Scsi, 0, sizeof(Scsi)); // clear out the SCSI CDB
Scsi[0] = XferCmd;
DWORD_AT(Scsi[2]) = MAKE_BIG_ENDIAN(SingleTransferLBA); // WHICH LBA to read, BIG endian
WORD_AT(Scsi[7]) = MAKE_BIG_ENDIAN(1); // a single sector
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
if (eax) {
// some sort of problem encountered!
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
SetErrorRecovery(true, false, true); // enable retries
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
if (eax) {
// failed with retries
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
SetErrorRecovery(true, true, true); // enable retries AND EEC
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
if (eax) {
// failed with retries and EEC
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
}
else { // succeeded with ECC
eax = 0x180101; // "ECC & Retries"
}
} // succeeded with retries
else {
eax = 0x170101; // "Read with Retries"
if (XferCmd == SCSI_Cmd_WriteMany)
eax = 0x0C8001; // "Wrote with Retries"
}
PostTheError:
BumpErrorCounts(eax); // given eax, count the errors
GetSpareSectorCounts(false); // update the Cart's Condition
UpdateRunTimeDisplay();
LocalBuffer += BYTES_PER_SECTOR;
SingleTransferLBA++;
if(UserInterrupt) break;
}
ProcessPendingMessages();
}
// now see whether we *did* found something to complain about ...
eax = SoftErrors + HardErrors;
if (eax == GlitchCount) {
// we missed it ... but SOMETHING happened! So let's report it ...
const long SavedSoftErrors = SoftErrors; // save the existing counts
const long SavedHardErrors = HardErrors;
eax = GlitchError; // get the error that triggered our search
long ebx = eax & 0x00FF00FF; // strip the ASCQ byte
if(ebx == 0x00110003) // if we're about to say "unrecovered read"
eax = 0x170101; // change it to: "Read with Retries"
BumpErrorCounts(eax); // given eax, count the errors
HardErrors = SavedHardErrors; // restore the counts
SoftErrors = SavedSoftErrors;
SoftErrors++;
UpdateRunTimeDisplay();
}
SingleTransferLBA = 0;
eax = 0; // now let's return happiness to our caller
if (HardErrors != InitialHardErrors) // UNRECOVERABLE errors!
eax = -1;
}
Exit:
SetErrorRecovery(true, true, false); // reenable Retries & ECC
return eax;
}
/*******************************************************************************
* TEST THE DISK
*******************************************************************************/
long TestTheDisk() {
void *pPatternBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
void *pUserDataBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
if(pPatternBuffer == NULL || pUserDataBuffer == NULL) {
printf("Allocation error\n");
return -1;
}
CartridgeStatus = DISK_TEST_UNDERWAY;
TestingPhase = TESTING_STARTUP; // inhibit stopping now
SetButtonText(szPressToStop);
LockCurrentDrive(); // prevent media removal
// Standard Testing Operation
StartingInstant = GetSystemTime();
do {
ProcessPendingMessages();
NumberOfLBAs = MAX_SECTORS_PER_TEST;
if(LastLBAOnCartridge) {
if (FirstLBASector + NumberOfLBAs > LastLBAOnCartridge + 1) {
NumberOfLBAs = LastLBAOnCartridge - FirstLBASector + 1;
}
// compute the percentage complete
PercentComplete = FirstLBASector * 100 / LastLBAOnCartridge;
}
if(NumberOfLBAs == 0) break;
// uppdate the elapsed time
SecondsElapsed = GetElapsedTimeInSeconds();
// get a random pattern of data to write
const long DataPattern = rand();
memset(pPatternBuffer, DataPattern, sizeof(pPatternBuffer));
// update the cartridge's status
GetSpareSectorCounts(false); // update the Cart's Condition
TestingPhase = READING_DATA;
UpdateRunTimeDisplay();
long eax = PerformRegionTransfer(SCSI_Cmd_ReadMany, pUserDataBuffer);
if(eax == 0) {
// -------------------------------
TestingPhase = WRITING_PATT;
UpdateRunPhaseDisplay();
PerformRegionTransfer(SCSI_Cmd_WriteMany, pPatternBuffer);
// -------------------------------
TestingPhase = READING_PATT;
UpdateRunPhaseDisplay();
PerformRegionTransfer(SCSI_Cmd_Verify, pPatternBuffer);
// -------------------------------
TestingPhase = WRITING_DATA;
UpdateRunPhaseDisplay();
PerformRegionTransfer(SCSI_Cmd_Verify, pUserDataBuffer);
}
else if (eax == LBA_TOO_LARGE) {
// if we hit the end of the disk ... exit gracefully!
goto GetOut;
}
if (CartridgeStatus != DISK_TEST_UNDERWAY) {
break;
}
// bump the FirstLBASector up for the next transfer
FirstLBASector += NumberOfLBAs;
} while(!UserInterrupt);
// show that we're post-test
GetOut:
free(pPatternBuffer);
free(pUserDataBuffer);
TestingPhase = UNTESTED;
UnlockCurrentDrive();
SetErrorRecovery(true, true, false); // reenable Retries & ECC
SetButtonText(szPressToStart);
CartridgeStatus = DISK_AT_SPEED;
UpdateRunTimeDisplay(); // added by mlt
// compute the number of serious troubles
long errors = FirmErrors + HardErrors;
if (errors >= BADNESS_THRESHOLD) {
return szBadResult;
}
else if (UserInterrupt) {
return szInterrupted;
}
else {
// it wasn't interrupted, nor seriously bad, was it perfect?
errors += SoftErrors;
if(errors) {
return szExplainResult;
} else {
return szPerfectResult;
}
}
}

View File

@ -0,0 +1,370 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <SIOUX.h>
#include <Windows.h>
#include <Quickdraw.h>
#include "tip.h"
WindowPtr tipWindow;
static int gDone;
static bool AllowColor;
static ControlHandle actionBtn = 0;
void NewTipWindow();
void DestroyTipWindow();
void DoEvent(EventRecord &event, RgnHandle *cursorRgn);
void DoUpdate(WindowPtr window);
void DoMouseDown(EventRecord &event);
void DoMouseMove(EventRecord &event, RgnHandle *cursorRegion);
void run_tip(void) {
RgnHandle cursorRgn = NewRgn();
NewTipWindow();
gDone = false;
do {
EventRecord event;
if (WaitNextEvent(everyEvent, &event, GetCaretTime(), cursorRgn)) {
DoEvent(event, &cursorRgn);
}
} while (!gDone);
DestroyTipWindow();
DisposeRgn(cursorRgn);
}
void NewTipWindow() {
OSErr error;
SysEnvRec theWorld;
error = SysEnvirons(1, &theWorld);
AllowColor = theWorld.hasColorQD;
Rect rect = qd.screenBits.bounds;
InsetRect(&rect, 50, 50);
rect.bottom = rect.top + 336 - 35;
rect.right = rect.left + 467;
Str255 title;
StrToPascal(title, szWindowTitle);
tipWindow = AllowColor ?
NewCWindow(NULL,&rect, title, true, 0, 0, true, 0) :
NewWindow(NULL,&rect, title, true, 0, 0, true, 0);
GetDC(hMainWnd);
if (AllowColor) {
SetColor(BACK_COLOR);
RGBColor bgColor;
GetForeColor(&bgColor);
RGBBackColor(&bgColor);
}
TextSize(10);
for(int i = 0; tipBtns[i].name; i++) {
if (!tipBtns[i].visible) continue;
SetRect(&rect,
tipBtns[i].x,
tipBtns[i].y,
tipBtns[i].x + tipBtns[i].w,
tipBtns[i].y + tipBtns[i].h
);
StrToPascal(title, tipBtns[i].name);
ControlHandle h = NewControl(tipWindow, &rect, title, true, 0, 0, 0, 0, tipBtns[i].id);
if(tipBtns[i].id == IDB_TEST) {
actionBtn = h;
}
}
ReleaseDC(hMainWnd);
}
void DestroyTipWindow() {
DisposeWindow(tipWindow);
}
void DoEvent(EventRecord &event, RgnHandle *cursorRgn) {
if(!SIOUXHandleOneEvent(&event)) {
// If SIOUX didn't handle the event, then handle it ourselves
switch(event.what) {
case mouseDown: DoMouseDown(event); break;
case updateEvt: DoUpdate((WindowPtr)event.message); break;
case osEvt: DoMouseMove(event, cursorRgn); break;
}
}
}
void DoUpdate(WindowPtr window) {
BeginUpdate(window);
SetPort(window);
EraseRect(&window->portRect);
GetDC(hMainWnd);
WndProc(WM_PAINT, 0);
DrawControls(window);
ReleaseDC(hMainWnd);
GetDC(hTestMonitor);
TestMonitorWndProc();
ReleaseDC(hTestMonitor);
EndUpdate(window);
}
void DoMouseDown(EventRecord &event) {
WindowPtr thisWindow;
ControlHandle thisControl;
int part = FindWindow(event.where, &thisWindow);
switch(part) {
case inSysWindow:
SystemClick(&event, thisWindow);
break;
case inContent:
if(thisWindow != FrontWindow()) {
SelectWindow(thisWindow);
}
else if(thisWindow == tipWindow) {
long id = 0;
Point mouse = event.where;
GetDC(hMainWnd);
GlobalToLocal(&mouse);
if(FindControl(mouse, thisWindow, &thisControl) == inButton) {
if(TrackControl(thisControl, mouse, 0) == inButton) {
id = GetControlReference(thisControl);
}
}
ReleaseDC(hMainWnd);
if(id) {
WndProc(WM_COMMAND, id);
}
}
break;
case inDrag:
DragWindow(thisWindow, event.where, &(*GetGrayRgn())->rgnBBox);
break;
case inGrow:
//DoGrowWindow(thisWindow, event);
break;
case inGoAway:
if (TrackGoAway(thisWindow, event.where)) {
gDone = true;
}
break;
}
}
void DoMouseMove(EventRecord &event, RgnHandle *cursorRgn) {
WindowPtr thisWindow;
int part = FindWindow(event.where, &thisWindow);
if (thisWindow == tipWindow) {
InitCursor();
// Set the cursorRegion to everything inside our window
if(cursorRgn) {
CopyRgn(((WindowPeek)tipWindow)->contRgn, *cursorRgn);
}
}
}
void StrToPascal(Str255 pStr, const char *str) {
size_t len = strlen(str);
pStr[0] = (len > 255) ? 255 : len;
strncpy((char*)pStr + 1, str, 255);
}
/*******************************************************************************
* SET COLOR
*******************************************************************************/
void SetColor(long color) {
if (AllowColor) {
if(color == BACK_COLOR) color = LTGRAY_COLOR;
// Use colors when available
RGBColor rgbColor;
rgbColor.red = (color & 0xFF0000) >> 8;
rgbColor.green = (color & 0x00FF00) >> 0;
rgbColor.blue = (color & 0x0000FF) << 8;
RGBForeColor(&rgbColor);
} else {
// Use patterns for B&W Macs
TextMode(srcCopy);
switch(color) {
case BACK_COLOR:
case WHITE_COLOR:
PenPat(&qd.white);
TextMode(srcBic);
break;
case BLACK_COLOR:
case GRAY_COLOR:
PenPat(&qd.black);
break;
case RED_COLOR:
case BLUE_COLOR:
PenPat(&qd.ltGray);
break;
case LTGRAY_COLOR:
case GREEN_COLOR:
PenPat(&qd.gray);
break;
}
}
}
void SetColor(long color, long monoColor) {
if (AllowColor) {
SetColor(color);
} else {
SetColor(monoColor);
}
}
/*******************************************************************************
* DRAW LED
*******************************************************************************/
void DrawLed(int x, int y, long color) {
Rect ledRect;
SetRect(&ledRect, x, y, x + 12, y + 12);
// Draw the LED
SetColor(color);
PaintOval(&ledRect);
if (AllowColor) {
// Draw a recessed outline
SetColor(BLACK_COLOR);
FrameOval(&ledRect);
SetColor(WHITE_COLOR);
FrameArc(&ledRect,45,180);
} else {
// Draw a non-recessed outline
SetColor(BLACK_COLOR);
FrameOval(&ledRect);
SetColor(WHITE_COLOR);
}
// Draw the reflection
if(color != BACK_COLOR) {
ledRect.left += 3;
ledRect.top += 3;
ledRect.right -= 7;
ledRect.bottom -= 7;
OffsetRect(&ledRect,0,1);
PaintRect(&ledRect);
OffsetRect(&ledRect,1,-1);
PaintRect(&ledRect);
}
}
/*******************************************************************************
* DRAW EDGE
*******************************************************************************/
void DrawEdge(Rect *qrc, int edge, int grfFlags) {
if(edge == BDR_SUNKENOUTER && AllowColor) {
// Draw a sunken rectangle
SetColor(GRAY_COLOR);
MoveTo(qrc->left,qrc->bottom-1);
LineTo(qrc->left,qrc->top);
LineTo(qrc->right-1,qrc->top);
SetColor(WHITE_COLOR);
MoveTo(qrc->left,qrc->bottom-1);
LineTo(qrc->right-1,qrc->bottom-1);
LineTo(qrc->right-1,qrc->top);
} else {
// Draw a non-recessed rectangle
SetColor(LTGRAY_COLOR);
FrameRect(qrc);
}
}
/*******************************************************************************
* RECTANGLE
*******************************************************************************/
void Rectangle(int left, int top, int right, int bottom) {
Rect rect;
SetRect(&rect, left, top, right, bottom);
PaintRect(&rect);
}
/*******************************************************************************
* TEXT OUT
*******************************************************************************/
void TextOut(int x, int y, Str255 pStr) {
FontInfo info;
GetFontInfo(&info);
MoveTo(x, y + info.ascent + info.descent);
DrawString(pStr);
}
void TextOut(int x, int y, const char *str) {
Str255 pStr;
StrToPascal(pStr, str);
TextOut(x, y, pStr);
}
void TextOutCentered(int x, int y, int w, int h, const char *str) {
// convert to Pascal string
Str255 pStr;
StrToPascal(pStr, str);
// now place the floating string in the middle
const int width = TextWidth(pStr, 0, strlen(str));
if(width < w) {
TextOut(x + w/2 - width/2, y, pStr);
}
}
/*******************************************************************************
* GET TEXT EXTENT
*******************************************************************************/
long GetTextExtent(const char *str, unsigned long len) {
// convert to Pascal string
Str255 pStr;
StrToPascal(pStr, str);
// now place the floating string in the middle
return TextWidth(pStr, 0, len);
}
/*******************************************************************************
* GET SYSTEM TIME
*******************************************************************************/
unsigned long GetSystemTime() {
unsigned long time;
GetDateTime (&time);
return time;
}
/*******************************************************************************
* SET BUTTON TEXT
*******************************************************************************/
void SetButtonText(const char *str) {
Str255 pStr;
StrToPascal(pStr, str);
if(actionBtn) {
GetDC(hMainWnd);
SetCTitle(actionBtn, pStr);
ReleaseDC(hMainWnd);
}
}
/*******************************************************************************
* POST QUIT MESSAGE
*******************************************************************************/
void PostQuitMessage() {
gDone = true;
}
/*******************************************************************************
* PROCESS PENDING MESSAGES
*******************************************************************************/
void ProcessPendingMessages() {
EventRecord event;
if (GetNextEvent(everyEvent, &event)) {
DoEvent(event,NULL);
}
}

View File

@ -0,0 +1,145 @@
#include "tip.h"
const char *szWindowTitle = "TIP 2.1b -- Zip & Jaz Drive and Cartridge Testing System";
const char *szCopyright_1 = "Copyright (c) 2006 by";
const char *szCopyright_2 = "Gibson Research Corp.";
const char *szSide0 = "Side 0";
const char *szSide1 = "Side 1";
const char *szSpaceDashSpace = " - ";
const char *szBarChartPercent = " %ld%% ";
const char *szCenteredDecimal = "%ld";
const char *szCenteredHex = "ErrorCode: %06lX";
const char *szHoursMinsSecs = "%ld:%02ld:%02ld";
const char *szCartStatus = "Cartridge Status:";
const char *szEstimating = "Estimating ...";
const char *szOneMoment = "--- --- ---";
const char *szPressToStart = "Press to Begin";
const char *szPressToStop = "Press to Stop";
const char *szPressToSpin = "Press to Spin Up";
const char *szPressToEject = "Press to Eject";
const char *szPressToProceed = "Press to Proceed";
/************* Cartridge Status Text *************/
const char *szUnknownStat = "Ejecting Cartridge";
const char *szAtSpeedStat = "Ready to Test";
const char *szSpinningUp = "Spinning Up";
const char *szNotPresent = "Awaiting Cartridge";
const char *szSpunDown = "Not Spinning";
const char *szStalledStat = "Stalled Error";
const char *szZtrackFailure = "Z-Tracks Failure !!";
const char *szDiskLocked = "Disk Protected";
const char *szLowSpares = "Low Spares Count";
const char *szTestUnderway = "Testing Drive ";
const char *DriveUnderTest = "X: ...";
const char *szTestFailure = "Testing Failed";
const char *szNoIomegaDrives = "No Iomega Drives";
const char *CartStatStrings[] = {
szUnknownStat, szAtSpeedStat, szSpinningUp,
szNotPresent, szSpunDown, szStalledStat,
szZtrackFailure, szDiskLocked, szLowSpares,
szTestUnderway, szTestFailure
};
ErrorTypeList errorTypeList[] = {
0x00000000, "-- None So Far --",
0x001C0000, "Missing Defect List",
0x000C0101, "Wrote with Realloc",
0x000C8001, "Wrote with Retries",
0x000C8101, "Wrote with Off Track",
0x000C8201, "Wrote w/o SectorMark",
0x000C8301, "Wrote with ID skip",
0x00170101, "Read with Retries",
0x00170601, "Retried & Realloc",
0x00180001, "Data Corrected",
0x00180101, "ECC & Retries",
0x00180201, "ECC & Realloc'd",
0x001C8F01, "Defect List Recvr'd",
0x00040002, "Drive Not Ready",
0x00040102, "Drive Going Ready",
0x00040202, "Drive Not Ready #2",
0x00040302, "Drive Needs Help",
0x00040402, "Not Rdy - Formating",
0x00300002, "Incompatible Media",
0x003A0002, "Media Not Present",
0x00010003, "Missing Sector Mark",
0x00030003, "Off Track Write",
0x00100003, "Bad ID Checksum",
0x00110003, "Unrecovered Read",
0x00118003, "Unrecovered Read",
0x00120003, "MissingID Sync",
0x00130003, "Missing Addr Mark",
0x00140003, "Sector Not Found",
0x00160003, "Sync Mark Missing",
0x001C0003, "Defect List Error",
0x00310003, "Corrupt Media Format",
0x00310103, "Format Command Fail",
// 0x0031xx03, " -- failures --"
0x00320003, "No Spare Sectors", // abort on this
0x00328F03, "No Spare Tracks", // abort on this
0x00018104, "Missing Sector Pulse",
0x00090004, "Track Follow Error",
0x00150004, "Head Seek Failure",
0x00220004, "Cartridge Sense Fail",
// 0x0040xx04, "Self Test Failed",
0x00470004, "Data Parity Error",
// 0x00xx0004, "Vendor Specific Error",
0x00290006, "I/O Bus Reset Error",
0x0088010B, "Reassigned Blk Err",
0x0088020B, "Side Switch Error",
0x00FFFFE6, "Buffer Too Big",
0xFFFFFFFF, "-- Unknown Error --",
0, 0
};
/****************** Control Text *****************/
const char *szBack = "< Back";
const char *szNext = "Next >";
const char *szQuit = "Exit";
/*******************************************************************************
* PERFORM_TEST_PAGE
*******************************************************************************/
TextList TestBlackText[] = {
{250, 2, "Data Read"},
{350, 2, "Patt Write"},
{250, 18, "Data Write"},
{350, 18, "Patt Read"},
{11, 39, "0%"},
{377, 39, "100%"},
{ 11, 77, "0"},
{377, 77, "100%"},
{ 22, 154, "Sectors"},
{ 10, 171, "Last Error"},
{ 17, 188, "Elapsed"},
{ 13, 205, "Time Left"},
{278, 154, "Soft Errors"},
{275, 171, "Firm Errors"},
{272, 188, "Hard Errors"},
{271, 205, "Total Errors"},
{0,0,0}
};
TextList TestGrayText[] = {
{155, 39, "Testing Progress"},
{129, 77, "Spare Sectors Consumed"},
{61, 135, "Testing Location"},
/*{219, 135, "Sound"},*/
{297, 135, "Error Summary"},
{0,0,0}
};