Compare commits

...

20 Commits

Author SHA1 Message Date
Marcio T 4793ffc0d8 Adopt standard GPL header. 2022-03-08 06:57:14 -07:00
Marcio T b6fa1cad7a Updated README 2022-03-06 17:41:39 -07:00
Marcio T 7d96b63ef0
Update README.md 2022-02-13 18:04:13 -07:00
Marcio T c719c8d7dd Major enhancements for Jaz drives
- Added command to spin down cartridges to command line
- Improved console diagnostics
  - Report SCSI short reads
  - Report last error
  - Report media change
  - Report disk at speed
  - Report spare sectors
  - Report detailed testing steps
- Supress unsuported commands on Jaz drive while:
  - Enabling early recovery
  - Reading defects list
- Fix short reads on Jaz drives during:
  - Cartridge status
  - Set error recovery
2022-02-13 17:34:14 -07:00
Marcio T dcfa0958a6 Added link to Steve Gibson's video. 2021-12-09 10:03:59 -07:00
Marcio T bfa9014432
Update README.md 2021-12-07 20:35:46 -07:00
Marcio T 6b36dfdc0e
Update README.md 2021-12-07 20:31:13 -07:00
Marcio T 49ce1bc093 Bug fixes; added YouTube image. 2021-12-07 20:24:17 -07:00
Marcio T afb8d6fe8f Update README, bug fixes. 2021-12-06 12:55:21 -07:00
Marcio T efd84f0ebc Fix error notification. 2021-12-05 21:29:54 -07:00
Marcio T 4ab4a0cc90 Whitespace fix. 2021-12-05 21:14:27 -07:00
Marcio T bfdf0d8171 Updated binary files. 2021-12-05 21:02:25 -07:00
Marcio T a90cdf000f Many bug fixes and improvements
- Fixed incorrect reporting of soft errors as hard errors
- Fixed disk change detection
- Fixed Jaz handling
- Improved status reporting
- Improved screen refresh
2021-12-05 20:57:34 -07:00
Marcio T 98edb49670 Fixes for B&W Macs, added frame around splash graphics. 2021-12-05 13:42:28 -07:00
Marcio T 37dab8d0b7 Added introduction page. 2021-12-05 13:31:11 -07:00
Marcio T b5f0328beb Automatically adjust buffer size based on available memory. 2021-12-05 13:30:48 -07:00
Marcio T 1af5e74aea Added speaker toggle 2021-12-04 17:33:52 -07:00
Marcio T 5ab24df256 Merge branch 'main' of github.com:marciot/grc-tip 2021-12-01 12:23:57 -07:00
Marcio T b00a01b948 Bug fixes. 2021-12-01 12:23:36 -07:00
Marcio T d21a0c277b
Update README.md 2021-12-01 08:39:51 -07:00
23 changed files with 657 additions and 237 deletions

View File

@ -8,6 +8,15 @@ This is the repository for a Macintosh port of [Gibson Research Corp]'s
Jaz Drives. A big thanks goes to Steve Gibson for the x86 source that
made this project possible!
[![Trouble in Paradise Demonstration](https://github.com/marciot/mac-tip/raw/main/images/youtube.png)](https://youtu.be/vtBlOaG2pNw)
:tv: See a demo on [YouTube]!
[![Mention in Steve Gibson's Security Now Podcast](https://github.com/marciot/mac-tip/raw/main/images/security-now.png)](https://twit.tv/shows/security-now/episodes/845)
:tv: Watch Steve Gibson react to my unusual request in the November 16th
episode of the "Security Now" podcast at the 1:05:10 mark.
Compatibility
-------------
@ -20,17 +29,19 @@ Power Macintosh G3, released in 1997.
It has been tested in on the following environments:
| Computer | Memory | System | Drive | Firmware |
|------------------- |--------|--------|-------------------------|----------|
| Macintosh Plus | 4MB | 7.0.1 | Zip Plus 100 Ext. SCSI | J.66 |
| PowerBook 3400c | 144MB | 8.6 | Zip 100 Ext. SCSI | E.08 |
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Ext. SCSI | C.22 |
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Int. SCSI | J.03 |
| Computer | Memory | System | Drive | Firmware |
|------------------- |--------|--------|-------------------------------------|----------|
| Macintosh Plus | 4MB | 7.0.1 | Zip Plus 100 Ext. SCSI | J.66 |
| PowerBook 3400c | 144MB | 8.6 | Zip 100 Ext. SCSI | E.08 |
| PowerBook 3400c | 144MB | 8.6 | Jaz 2GB Ext. SCSI w/ 1GB media | E.17 |
| PowerBook 3400c | 144MB | 8.6 | Jaz 2GB Ext. SCSI w/ 2GB media | E.17 |
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Ext. SCSI | C.22 |
| Power Macintosh G3 | 256MB | 9.2.1 | Zip 100 Int. SCSI | J.03 |
What will not work or is missing:
* USB connected Zip drives have been reported to not work.
* The functionality for operating with password or write protected disks is missing.
* The functionality for operating with password or write protected disks has not been ported.
* The partition recovery feature has been removed, since it is meant for PC disks.
</details>
@ -47,13 +58,9 @@ port.**
Where are the binaries?
-----------------------
Once they are ready, compiled binaries will be made available on the
releases page for people who have signed up for
Compiled binaries are available on the releases page for people who have signed up for
[beta testing in the discussion forum]
There is always a risk of data loss with a tool like this, so please
use it only on non-critical data if you decide to beta test.
How can you help?
-----------------
@ -61,8 +68,14 @@ You can help this project in one of the following ways:
* Star this project on GitHub to show your support!
* Sign up to [beta testing in the discussion forum]!
* Donate a 1 or 2GB Jaz cartridge for testing (I have a 2GB SCSI Jaz drive, but no cartridges!).
* Become a GitHub sponsor to help fund my work with this and other open-source projects!
* Become a GitHub sponsor to help fund my various open-source projects!
Other Vintage Macintosh Stuff
-----------------------------
* [MiniVNC]: A remote desktop server for vintage Macintoshes!
* [ScreenChooser]: A dynamic background changer for vintage Macintoshes!
* [Retroweb Vintage Computer Museum]: A web-based museum of vintage computers, including the Macintosh!
Got work?
---------
@ -74,20 +87,22 @@ for vintage Macs. If you have a project in mind, please hit me up via my
Unmounting volumes
------------------
**To avoid data corruption, you must "unmount" the cartridge prior to
**To avoid data corruption, a cartridge must be unmounted prior to
starting a test with TIP!**
There is no way to unmount a cartridge (without also ejecting it) in the
Finder, but you can either:
The best way to accomplish this is to start TIP without a disk in the drive you want to test.
Then, insert the cartridge at the testing screen which indicates "Awaiting media...". TIP
will recognize it if Mac OS mounts newly inserted cartridge and will give you the choice to
unmount it.
1) Start TIP without a disk in the drive. TIP will recognize when Mac OS mounts newly inserted cartridges and will give you the choice to unmount it.
2) Use the command console to unmount a disk **prior to** starting TIP
Alternatively, you can use the command line from the "Advanced" menu to unmount a disk
**prior to** starting a test.
<details>
<summary>Click here to learn how to use the Command Console</summary></br>
<summary>Click here to learn how to use the command line</summary></br>
The Command Console shows up when you first start the program. This is a
unique feature of this port and is not present in the original TIP:
The command line is accessible by selecting run "Run Command Line..." from the "Advanced"
menu. This is a unique feature of this port and is not present in the original TIP:
![Command Line][mac-screenshot2]
@ -104,15 +119,10 @@ cartridge will remain in the drive. To unmount a drive:
*The unmount process will fail if you have any open files or applications in
the volume; if this happens, close those files and try again.*
### Starting TIP
To start TIP, you will need to tell it which SCSI device to use:
### Listing SCSI devices
* Type `list` to show a numbered list of all SCSI devices by SCSI ID.
* Type `tip` followed by a SCSI ID to run TIP on that device.
Future versions of this tool may eliminate the Command Console, if I can find
the right way to automate all these steps in MacOS :grin:
</details>
About the code
@ -145,6 +155,7 @@ Credits
* Thank you to [Stone Table Software] for providing the tool I used to convert the Windows RTF docs into SimpleText...
* ...and to the Internet Archive's Wayback Machine for allowing me to access it long after the website was shut down!
* Thank you to Thomas Tempelmann sharing his [LaunchLib code] which I used to open the documents
* Thank you to Grant Hutchinson and Nikola Biscan for sending me 1GB and 2GB Jaz cartridges for testing.
The Original TIP For Windows
----------------------------
@ -164,7 +175,7 @@ his code in this repository with his permission.
![TIP Running on a Mac Plus][mac-plus]
[GitHub account]: https://github.com/marciot
[mac-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip1.png "Mac TIP Testing Screen"
[mac-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip1.gif "Mac TIP Animation"
[mac-screenshot2]: https://github.com/marciot/mac-tip/raw/main/images/mac-cmd.png "Mac TIP Command Line"
[mac-screenshot3]: https://github.com/marciot/mac-tip/raw/main/images/mac-tip-cw8.png "Mac TIP Build Environment"
[win-screenshot1]: https://github.com/marciot/mac-tip/raw/main/images/win-tip1.gif "Windows TIP About Screen"
@ -178,3 +189,9 @@ his code in this repository with his permission.
[beta testing in the discussion forum]: https://github.com/marciot/mac-tip/discussions/1
[LaunchLib code]: http://www.tempel.org/macdev/index.html#Libs
[Stone Table Software]: https://web.archive.org/web/20010308062807/http://www.stonetablesoftware.com/rtf2text.html
[ScreenChooser]: https://archive.org/details/screen-chooser
[YouTube]: https://youtu.be/vtBlOaG2pNw
[Retroweb Vintage Computer Museum]: http://retroweb.maclab.org
[MiniVNC]: https://github.com/marciot/mac-minivnc

BIN
images/mac-tip1.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

BIN
images/security-now.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 KiB

BIN
images/youtube.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 465 KiB

View File

@ -12,32 +12,13 @@ void main() {
SIOUXSettings.leftpixel = 8;
SIOUXSettings.toppixel = 44;
printf(
"\n\n"
"Trouble in Paradise\n"
"===================\n\n"
"A Macintosh port of \"Trouble in Paradise\" for Windows, made possible by a\n"
"generous code donation by Steve Gibson from Gibson Research Corporation.\n\n"
"This freeware utility determines whether an Iomega Zip or Jaz drive is prone\n"
"to developing the dreaded \"Click of Death\" (COD) syndrome. Steve Gibson's\n"
"research into the maintenance, repair and data recovery of Iomega's removable\n"
"media mass storage products led to this capability.\n\n"
);
printf( "------------------------------------------------------------------------------\n" );
printf( "This Mac port (c) 2021 Marcio Teixeira http://github.com/marciot/mac-tip\n" );
printf( "Based on code (c) 2006 Gibson Research Corp http://grc.com/tip/clickdeath.htm\n" );
printf( "------------------------------------------------------------------------------\n" );
printf("\nStarting tip ...\n");
SIOUXSetTitle("\pTrouble in Paradise for Macintosh (" __DATE__ ")");
// Confirm that the user wants to run TIP
char cmd[80];
printf("\n\nThis program is in BETA TESTING and may cause data loss!\n\nProceed [Y/N]? ");
gets( cmd );
if(tolower(cmd[0]) == 'y') {
run_tip();
printf("\n\nYou may need to REBOOT your Mac before cartridges are recognized by Mac OS.");
}
run_tip();
}

Binary file not shown.

View File

@ -14,7 +14,8 @@ void mac_list_volumes() {
for (;;) {
OSErr err = PBHGetVInfo(&paramBlock, false);
if (err == nsvErr) break;
printf(" %d: %#s\n", paramBlock.volumeParam.ioVolIndex, paramBlock.volumeParam.ioNamePtr);
size_t size = paramBlock.volumeParam.ioVAlBlkSiz * paramBlock.volumeParam.ioVNmAlBlks;
printf("%4d: [%7.2f MBs] %#s\n", paramBlock.volumeParam.ioVolIndex, float(size)/1024/1024, paramBlock.volumeParam.ioNamePtr);
paramBlock.volumeParam.ioVolIndex++;
}
}
@ -23,7 +24,7 @@ OSErr mac_get_drive_volumes(int driveNum, Str255 str) {
HParamBlockRec paramBlock;
Str255 volName;
Boolean first = true;
str[0] = '\0';
paramBlock.volumeParam.ioCompletion = 0;
paramBlock.volumeParam.ioNamePtr = volName;
paramBlock.volumeParam.ioVRefNum = 0;
@ -65,6 +66,38 @@ OSErr mac_unmount_drive(int driveNum) {
}
}
OSErr mac_mount_drive(int driveNum) {
ParamBlockRec paramBlock;
paramBlock.volumeParam.ioVRefNum = driveNum;
OSErr err = PBMountVol(&paramBlock);
return err;
}
OSErr mac_mount_drives() {
const QHdrPtr qh = GetDrvQHdr();
for(DrvQElPtr qe = (DrvQElPtr) qh->qHead; qe; qe = (DrvQElPtr) qe->qLink) {
OSErr err = mac_mount_drive(qe->dQDrive);
switch(err) {
case volOnLinErr: continue;
default: printf("Error %d while mounting drive %d\n", err, qe->dQDrive);
}
}
return noErr;
}
OSErr mac_list_drives() {
Str255 volumeNames;
const QHdrPtr qh = GetDrvQHdr();
for(DrvQElPtr qe = (DrvQElPtr) qh->qHead; qe; qe = (DrvQElPtr) qe->qLink) {
size_t size = size_t(qe->dQDrvSz) | ((qe->qType == 1) ? size_t(qe->dQDrvSz2) << 16 : 0) ;
mac_get_drive_volumes(qe->dQDrive, volumeNames);
printf("%4d: [%7.2f MBs] %#s\n", qe->dQDrive, float(size)/2/1024, volumeNames);
}
return noErr;
}
void mac_unmount(int id) {
HParamBlockRec paramBlock;
paramBlock.volumeParam.ioCompletion = 0;

View File

@ -3,3 +3,6 @@ void mac_unmount(int id);
void mac_eject(int id);
OSErr mac_get_drive_volumes(int driveNum, Str255 str);
OSErr mac_unmount_drive(int driveNum);
OSErr mac_mount_drive(int driveNum);
OSErr mac_mount_drives();
OSErr mac_list_drives();

View File

@ -130,6 +130,9 @@ bool TBMouseDown( TBHandle tb, Point where, WindowPtr whichWindow ) {
HLock( (Handle) tb );
TBRec &my = **tb;
// Return if hidden
if((*my.scroll)->contrlVis == 0) return 0;
ControlHandle whichCntl;
short partCode = FindControl(where, whichWindow, &whichCntl);
if (partCode) {
@ -189,7 +192,7 @@ void TBSetScroll( TBHandle tb, short scroll ) {
my.lastV = scroll;
}
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec) {
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec, bool redraw) {
short fRefNum;
TBSetScroll(tb, 0);
@ -236,7 +239,7 @@ OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec) {
Handle hStyle = Get1Resource('styl', 128);
if (hStyle) {
HNoPurge(hStyle);
TEUseStyleScrap(0, dataSize, (StScrpHandle) hStyle, true, my.tbox);
TEUseStyleScrap(0, dataSize, (StScrpHandle) hStyle, redraw, my.tbox);
TECalText(my.tbox);
ReleaseResource(hStyle);
}

View File

@ -28,4 +28,4 @@ void TBUpdate( TBHandle html );
void TBResize( TBHandle html, const Rect *r );
void TBSetScroll( TBHandle html, short scroll );
bool TBMouseDown( TBHandle html, Point where, WindowPtr whichWindow );
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec);
OSErr TBReadSimpleText( TBHandle tb, const FSSpec *docSpec, bool redraw);

View File

@ -38,19 +38,24 @@ bool process_command() {
printf("\n");
char *arg_str = strchr(cmd, ' ');
while(*arg_str == ' ') arg_str++;
if(arg_str) arg_val = atoi(arg_str);
if(arg_str) {
while(*arg_str == ' ') 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 'p': iomega_spin_down_cartridge(arg_val); break;
case 'r': scsi_reset(); break;
case 'e': mac_eject(arg_val); break;
case 'i': dev_info(arg_val); break;
case 'v': mac_list_volumes(); break;
case 'u': mac_unmount(arg_val); break;
case 'q': return false;
case 'd': mac_list_drives(); break;
case 'm': if(arg_str) mac_mount_drive(arg_val); else mac_mount_drives(); break;
default: printf("Unknown command, type 'h' for help\n");
}
return true;
@ -62,10 +67,15 @@ void print_help() {
" help : print this help\n"
" quit : exit the command line\n"
"\nMacintosh commands:\n"
"\nMacintosh volume commands:\n"
" volumes : list Mac volumes\n"
" unmount [n] : unmount a volume\n"
" eject [n] : eject a volume\n"
" unmount [n] : unmount a volume\n"
"\nMacintosh drive commands:\n"
" drives : list all drives\n"
" mount [n] : mount a drive\n"
" mount : mount all drives\n"
"\nGeneral SCSI operations:\n"
" reset : reset the SCSI bus\n"
@ -74,6 +84,7 @@ void print_help() {
"\nIomega device operations on SCSI device:\n"
" spin [n] : spin up a cartridge\n"
" pause [n] : spin down a cartridge\n"
);
}
@ -84,9 +95,9 @@ void scan_bus() {
for( id=0; id<8; id++ ) {
err = scsi_inquiry( id, 0, &reply);
if( err != 0 ) {
printf( " %hd: (Not installed)\n", id );
printf( "%4hd: (Not installed)\n", id );
} else {
printf( " %hd: ", id );
printf( "%4hd: ", id );
printn( reply.vend, 8 );
printf( ", " );
printn( reply.prod, 16 );

View File

@ -29,6 +29,19 @@ OSErr iomega_spin_down_and_eject( int id ) {
return scsi_cmd(id, cmd, sizeof(cmd), 0, 0, 0, 0);
}
OSErr iomega_spin_down_cartridge( int id ) {
// issue an Asynchronous STOP command to induce spindown
char cmd[6] = {
SCSI_Cmd_StartStopUnit,
1, // set the IMMED bit for offline
0,
0,
0,
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] = {

View File

@ -4,5 +4,6 @@ typedef Boolean bool;
OSErr iomega_spin_up_cartridge(int id);
OSErr iomega_spin_down_and_eject(int id);
OSErr iomega_spin_down_cartridge(int id);
OSErr iomega_set_prevent_removal(int id, bool lock);
OSErr iomega_eject_cartridge(int id);

View File

@ -5,7 +5,7 @@
#include <stdlib.h>
#include <string.h>
#define READ_TIMEOUT 60 /* 300 ticks = 5 seconds */
#define READ_TIMEOUT 180 /* 300 ticks = 5 seconds */
OSErr scsi_reset() {
return SCSIReset();
@ -61,18 +61,21 @@ OSErr scsi_cmd(int id, void *cmd, size_t clen, void *buff, size_t siz, size_t cn
case SCSI_READ: io_err = SCSIRead( (Ptr) TIB ); break;
default: break;
}
if (io_err != noErr) {
printf("SCSI Read/Write Error: %d\n", io_err);
if (io_err == scPhaseErr && flags & SCSI_READ) {
printf("\nSCSI phase error; less data delivered than requested\n");
}
else if (io_err != noErr) {
printf("\nSCSI Read/Write Error: %d\n", io_err);
}
} else {
printf("SCSICmd Error: %d\n", err);
}
/* Complete the transaction and release the bus */
short cstat, cmsg;
short cstat = 0, cmsg = 0;
OSErr comperr = SCSIComplete( &cstat, &cmsg, READ_TIMEOUT );
if(status) *status = cstat;
if (comperr != noErr) {printf("SCSIComplete Error: %d (status: %d)\n", err, cstat); return err;}
if (comperr != noErr) {printf("SCSIComplete Error: %d (status: %d)\n", comperr, cstat); return err;}
return err;
}

View File

@ -8,16 +8,17 @@
#include "tip.h"
// ----------------------- Test Monitor Panel Definitions -------------------
#define SET_RECT(LEFT, TOP, RIGHT, BOTTOM) {TOP, LEFT, BOTTOM, RIGHT}
#define TITLE_TOP 11
#define BODY_TOP 54
#define BODY_LEFT 156
#define BODY_RIGHT 445
#define BODY_BOTTOM 280
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);
#define BODY_WIDTH (BODY_RIGHT - BODY_LEFT)
#define BODY_HEIGHT (BODY_BOTTOM - BODY_TOP)
#define LOGO_1_LEFT 157
#define LOGO_1_TOP 57
/*******************************************************************************
* WinMain
@ -41,6 +42,22 @@ void WinMain(uint8_t *DrivesSkipped) {
StartApplicationTimer();
}
/*******************************************************************************
* PAINT 3D HEADLINE
*******************************************************************************/
void Paint3DHeadline(const char *pszText, int Xleft, int Ytop) {
TextSize(24);
TextFace(bold);
TextFont(helvetica);
SetColor(WHITE_COLOR);
TextOut(Xleft, Ytop, pszText);
SetColor(BLACK_COLOR);
TextOut(Xleft+1, Ytop+1, pszText);
TextFont(applFont);
TextFace(0);
TextSize(10);
}
/*******************************************************************************
* WndProc
*
@ -53,17 +70,80 @@ void WndProc(long iMessage, uint16_t wParam) {
if (iMessage == WM_PAINT) {
// Draw the Lower Horz Button Divider
GetDC(hMainWnd);
SetColor(GRAY_COLOR);
MoveTo(15, 289);
LineTo(446, 289);
SetColor(WHITE_COLOR);
LineTo(446, 290);
LineTo(14, 290);
ReleaseDC(hMainWnd);
// Draw the Gibson 'G' Logo
if(CurrentPage == INTRO_PAGE) {
GetDC(hIntroWnd);
SetColor(GRAY_COLOR, GRAY_COLOR);
MoveTo(LOGO_1_LEFT+1, LOGO_1_TOP+29);
LineTo(LOGO_1_LEFT+14, LOGO_1_TOP+29);
LineTo(LOGO_1_LEFT+14, LOGO_1_TOP+0);
SetColor(WHITE_COLOR, LTGRAY_COLOR);
LineTo(LOGO_1_LEFT+12, LOGO_1_TOP+0);
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+12);
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+30);
SetColor(GRAY_COLOR, GRAY_COLOR);
MoveTo(LOGO_1_LEFT+18, LOGO_1_TOP+14);
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+14);
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+12);
LineTo(LOGO_1_LEFT+34, LOGO_1_TOP+0);
SetColor(WHITE_COLOR, LTGRAY_COLOR);
LineTo(LOGO_1_LEFT+17, LOGO_1_TOP+0);
LineTo(LOGO_1_LEFT+17, LOGO_1_TOP+15);
SetColor(GRAY_COLOR, GRAY_COLOR);
MoveTo(LOGO_1_LEFT+33, LOGO_1_TOP+46);
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+46);
LineTo(LOGO_1_LEFT+46, LOGO_1_TOP+29);
LineTo(LOGO_1_LEFT+34, LOGO_1_TOP+17);
SetColor(WHITE_COLOR, LTGRAY_COLOR);
LineTo(LOGO_1_LEFT+32, LOGO_1_TOP+17);
LineTo(LOGO_1_LEFT+32, LOGO_1_TOP+47);
SetColor(GRAY_COLOR, GRAY_COLOR);
MoveTo(LOGO_1_LEFT+1, LOGO_1_TOP+35);
LineTo(LOGO_1_LEFT+12, LOGO_1_TOP+46);
LineTo(LOGO_1_LEFT+29, LOGO_1_TOP+46);
LineTo(LOGO_1_LEFT+29, LOGO_1_TOP+32);
SetColor(WHITE_COLOR, LTGRAY_COLOR);
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+32);
LineTo(LOGO_1_LEFT+0, LOGO_1_TOP+35);
// paint the 3D program title
Paint3DHeadline(szIntroTitle, BODY_LEFT, TITLE_TOP);
// now the rest of the stuff ...
SetColor(BLACK_COLOR);
#define WH_RECT(L,T,W,H) L, T, L + W, T + H
Rect rect;
SetRect(&rect, WH_RECT(221, BODY_TOP, 230, 60));
TETextBox(szIntroSubTitle, strlen(szIntroSubTitle), &rect, teFlushDefault);
SetRect(&rect, WH_RECT(BODY_LEFT, BODY_TOP+64, BODY_WIDTH, 115));
TETextBox(szIntroText, strlen(szIntroText), &rect, teFlushDefault);
// show the current logo bitmap
SplashTheBitmap();
ReleaseDC(hIntroWnd);
}
// Paint the Copyright Notice
GetDC(hMainWnd);
SetColor(GRAY_COLOR);
TextOut(15, 298, szCopyright_1);
TextOut(15, 311, szCopyright_2);
ReleaseDC(hMainWnd);
}
// -------------------------------------------------------------------------
// WM_COMMAND : a button was pressed
@ -81,7 +161,7 @@ void WndProc(long iMessage, uint16_t wParam) {
SpinUpIomegaCartridge(CurrentDevice);
break;
case DISK_AT_SPEED:
printf("Testing the disk\n");
printf("\nTesting the disk\n");
if(TestingPhase != READY_TO_TEST) {
PrepareToBeginTesting();
}
@ -97,6 +177,7 @@ void WndProc(long iMessage, uint16_t wParam) {
EjectIomegaCartridge(CurrentDevice);
break;
case DISK_LOW_SPARES:
CartridgeStatus = DISK_AT_SPEED;
SetRichEditText(szNotRunning);
SetWindowText(hTestButton, szPressToStart);
PrepareToBeginTesting();
@ -110,18 +191,6 @@ void WndProc(long iMessage, uint16_t wParam) {
}
}
BtnList tipBtns[] = {
{IDB_BACK, szBack, 157, 301, 80, 24},
{IDB_NEXT, szNext, 236, 301, 80, 24},
{IDB_QUIT, szQuit, 402, 301, 45, 24},
// For Mac TIP only
{IDB_TEST, szPressToStart, 157, 301, 150, 24},
{IDB_EXPL, "Explain", 330, 301, 60, 24},
{IDB_OKAY, "Okay", 380, 301, 65, 24},
{IDB_READ, "Open in SimpleText...", 210, 301, 160, 24},
{0, 0, 0, 0, 0, 0}
};
/*******************************************************************************
* SUNKEN FIELDS
*******************************************************************************/
@ -270,6 +339,15 @@ void PaintCenteredValue(int Xleft, int Ytop, int XWidth, int YHeight, long value
*
* This paints the two columns of testing statistics on the test minitor window.
*******************************************************************************/
char *FindErrorString(long error) {
char *errStr = 0;
for (int i = 0; errorTypeList[i].str; i++) {
errStr = errorTypeList[i].str;
if (errorTypeList[i].code == error) break;
}
return errStr;
}
void PaintTestStatistics(bool Active) {
char szString[40];
// assemble and paint the sector testing range
@ -292,12 +370,7 @@ void PaintTestStatistics(bool Active) {
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);
PaintCenteredString(76, 172, 126, 14, FindErrorString(LastError), Active);
// show the elapsed time
CvrtSecondsToHMSstring(szString, SecondsElapsed);
@ -369,7 +442,10 @@ void TestMonitorWndProc() {
PaintTextArray(TestGrayText, GRAY_COLOR);
PaintTestPhase();
// TODO: paint the little speaker icon
// paint the little speaker icon
Rect theRect;
SetRect(&theRect, 232, 191, 232+16, 191+16);
PlotIconID(&theRect, atTopLeft, 0, 129);
}
/*******************************************************************************
@ -436,5 +512,7 @@ void AllowProgramExit() {
*******************************************************************************/
void ErrorSound() {
SysBeep(10);
if(SendMessage(hSoundCheckbox, BM_GETCHECK) == BST_CHECKED) {
SysBeep(10);
}
}

View File

@ -1,14 +1,22 @@
#include <stdlib.h>
#include "ctype.h"
extern WindowPtr tipWindow;
void run_tip();
typedef enum TipPage {
INTRO_PAGE,
PERFORM_TEST_PAGE,
EXPLAIN_RESULTS,
} TipPage;
#define MINIMUM_JAZ_SPARES 500
#define MAXIMUM_JAZ_SPARES 2557
#define MINIMUM_ZIP_SPARES 50
#define MAXIMUM_ZIP_SPARES 126
extern TipPage CurrentPage;
extern long CurrentDevice;
extern long DriveCount;
extern long JazDrive; // true if the current drive
@ -16,6 +24,7 @@ extern long CartridgeStatus;
extern long LastLBAOnCartridge;
extern uint32_t StartingInstant;
extern long NumberOfLBAs;
extern long AdapterMaxSectors;
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;
@ -74,6 +83,8 @@ enum {
#define WM_COMMAND 2
#define SW_SHOW 1
#define SW_HIDE 2
#define BM_GETCHECK 1
#define BST_CHECKED 1
void SetRGBColor(long color, RGBColor *rgbColor);
void SetColor(long color);
@ -91,6 +102,7 @@ void SetWindowText(int id, const char *str);
void EnableWindow(int id, bool enabled);
void ShowWindow(ControlHandle hCntl, int state);
void ShowWindow(int id, int state);
long SendMessage(int id, int msg);
void InvalidateRect(int id);
void Rectangle(int left, int top, int right, int bottom);
void DrawEdge(Rect *qrc, int edge, int grfFlags);
@ -99,6 +111,8 @@ void StopApplicationTimer();
void PostQuitMessage();
unsigned long GetSystemTime();
bool PrepareDC(int which);
void SplashTheBitmap();
void Paint3DHeadline();
#define GetDC(h) {GrafPtr oldPort; \
GetPort(&oldPort); \
@ -141,6 +155,9 @@ enum {
/*******************************************************************************
* STRINGS
*******************************************************************************/
extern const char *szIntroTitle;
extern const char *szIntroSubTitle;
extern const char *szIntroText;
extern const char *szWindowTitle;
extern const char *szCopyright_1;
@ -221,15 +238,18 @@ extern const char *szQuit;
#define IDB_EXPL 0xFF04
#define IDB_OKAY 0xFF05
#define IDB_READ 0xFF06
#define IDB_BEEP 0xFF07
enum {
hDefault,
hMainWnd,
hTestMonitor,
hTestButton = IDB_TEST,
hExitButton = IDB_QUIT,
hTestButton = IDB_TEST,
hExitButton = IDB_QUIT,
hSoundCheckbox = IDB_BEEP,
// Extras added by MLT
hExplainWnd = IDB_EXPL
hIntroWnd = 5,
hExplainWnd = IDB_EXPL
};
typedef struct {
@ -239,10 +259,13 @@ typedef struct {
int y;
int w;
int h;
int type;
ControlHandle hndl;
} BtnList;
extern BtnList tipBtns[];
extern Rect CS_Stat, TP_Perc, SS_Jaz, SS_Sid0, TL_Sect, ES_Read, SE_Rect;
/*******************************************************************************
* FUNCTION PROTOTYPES
*******************************************************************************/
@ -259,6 +282,8 @@ void PaintTheBarGraphs(bool Active);
void PaintTestStatistics(bool Active);
void CvrtSecondsToHMSstring(char *szString, long seconds);
char *FindErrorString(long error);
void UpdateCurrentSector();
void UpdateRunTimeDisplay();
void UpdateRunPhaseDisplay();
@ -267,6 +292,7 @@ void AllowProgramExit();
void ErrorSound();
void ProcessPendingMessages();
void WinMain(uint8_t *DrivesSkipped);
void Paint3DHeadline(const char *pszText, int Xleft, int Ytop);
void WndProc(long iMessage, uint16_t wParam);
void TestMonitorWndProc();
void ApplicationTimerProc();
@ -274,12 +300,12 @@ void TestButtonClicked();
int GetDriveEntryOffset(short Device);
void GetCommandDetails(char command, char &cmd_flags, char &cmd_length);
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen);
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, size_t IoBufLen);
long EnumerateIomegaDevices(uint8_t *DrivesSkipped);
long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen);
long SetModePage(short Device, void *pBuffer);
long SetModePage(short Device, void *pBuffer, short BufLen);
void ModifyModePage(char *PageBuff, char eec, char retries);
void SetErrorRecovery(bool Retries, bool ECC, bool Testing);
long SetErrorRecovery(bool Retries, bool ECC, bool Testing);
long GetNonSenseData(short Device, short DataPage, void *Buffer, short BufLen);
long LockCurrentDrive();
long UnlockCurrentDrive();
@ -287,9 +313,9 @@ void UnlockAllMedia();
long SpinUpIomegaCartridge(short Device);
void EjectAllMedia();
long GetSpareSectorCounts(char);
uint8_t GetCartridgeStatus(long Device);
uint8_t GetCartridgeStatus(long Device, uint8_t flags);
void HandleDriveChanging();
void SetCartridgeStatusToEAX(long eax);
void SetCartridgeStatusToEAX(long eax, uint8_t flags);
void EjectIomegaCartridge(int Device);
long PerformRegionTransfer(short XferCmd, void *pBuffer);
void TestTheDisk();

View File

@ -6,8 +6,28 @@
#include "tip.h"
//#define DEMO
/* The original TIP seems to request more data than is supplied by
* certain commands. While this appears to be allowed, it causes
* SCSI phase errors to be reported. Setting NO_EXCESS_READS will
* adjust the reads to to the max size before such errors occur.
*/
#define NO_EXCESS_READS
/* The original TIP will always try to enable Early Recovery. This
* fails on certain Jaz drives. While the original TIP will then
* retry without Early Recovery, this will cause many errors to be
* reported. Enable SUPRESS_ER_ERRORS to prevent this from problem
* from happening as frequently
*/
#define SUPRESS_ER_ERRORS
/* The original TIP will always try to read the defects list, but
* not all drives support this, causing many errors to be shown.
* Setting SUPPRESS_DEFECTS_ERROR will silence these errors.
*/
#define SUPPRESS_DEFECTS_ERROR
#define MAKE_LITTLE_ENDIAN(a) a // Don't do anything on 68000
#define MAKE_BIG_ENDIAN(a) a // Don't do anything on 68000
@ -71,10 +91,10 @@ struct DEFECT_LIST_HEADER {
#define DRIVE_A_SUPPORT_BIAS 32 // reduce total by 32 for DRIVE A support
#define BYTES_PER_SECTOR 512
#define MAX_SECTORS_PER_TEST 25
#define BYTES_PER_SECTOR 512
#define MAX_SECTORS_PER_TEST 128
#define BADNESS_THRESHOLD 10
#define BADNESS_THRESHOLD 10
#define SS_ERR 0x00000004
#define DEFECT_LIST_READ_ERROR 0x001c0003
@ -89,12 +109,20 @@ struct DEFECT_LIST_HEADER {
#define CHECK_CONDITION 0x02
TipPage CurrentPage;
long CurrentDevice = -1; // the device that's been recognized
long DriveCount = 0;
long JazDrive = 0; // true if the current drive
long CartridgeStatus = DISK_NOT_PRESENT;
#ifdef SUPRESS_ER_ERRORS
Boolean SupressEarlyRecovery = false;
#endif
#ifdef SUPPRESS_DEFECTS_ERROR
Boolean SupressDefectsError = false;
#endif
unsigned long StartingInstant;
// ----------------------------- Run Time Variables ------------------------------
@ -108,6 +136,7 @@ long TestingPhase = 0; // 0 = not testing, no data ...
long PercentComplete;
long FirstLBASector;
long NumberOfLBAs;
long AdapterMaxSectors;
long LastLBAOnCartridge;
long SecondsElapsed;
long SoftErrors;
@ -188,12 +217,14 @@ void GetCommandDetails(char command, char &cmd_flags, char &cmd_length) {
* 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) {
long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, size_t 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) {
// else, if it's *NOT* a "Sense Data" error (SS_ERR)
LastError = err | 0x00FFFF00; // [00 FF FF er]
return SS_ERR;
}
if(cmd_status == 0) {
@ -207,15 +238,16 @@ long SCSICommand(short Device, char *lpCmdBlk, void *lpIoBuf, short IoBufLen) {
printf("SCSI CHECK CONDITION (KEY %x, ASC %x, ASCQ %x)\n", sense_data.key, sense_data.asc, sense_data.ascq);
// okay, we have an SS_ERR condition, let's check the SENSE DATA
// assemble [00 ASC ASCQ SenseKey]
long res = (long(sense_data.asc) << 16) |
(long(sense_data.ascq) << 8) |
(long(sense_data.key) );
const long res = (long(sense_data.asc) << 16) |
(long(sense_data.ascq) << 8) |
(long(sense_data.key) );
if(res == MEDIA_CHANGE_CODE) {
printf("Media change signalled. Most recent error can be ignored\n\n");
int index = GetDriveEntryOffset(Device);
DriveArray[index].flags |= MEDIA_CHANGED;
return 0;
}
return 0;
return res;
}
else {
// else, if it's *NOT* a "Sense Data" error (SS_ERR)
@ -274,7 +306,7 @@ long EnumerateIomegaDevices(uint8_t *DrivesSkipped) {
// On the Mac, we want to ignore drives that have media in them at
// program entry, as this means the volume is mounted in Mac OS
const bool driveEmpty = GetCartridgeStatus(Device) == DISK_NOT_PRESENT;
const bool driveEmpty = (GetCartridgeStatus(Device, flags) == DISK_NOT_PRESENT);
if(driveEmpty) {
DriveArray[DriveCount].flags = flags;
DriveArray[DriveCount].scsi_id = Device;
@ -308,13 +340,18 @@ long GetModePage(short Device, short PageToGet, void *pBuffer, short BufLen) {
/*******************************************************************************
* SET MODE PAGE
*******************************************************************************/
long SetModePage(short Device, void *pBuffer) {
char* ebx = (char*) pBuffer; // get a pointer to the top of buffer
char ecx = ebx[0] + 1; // adjust it up by one
long SetModePage(short Device, void *pBuffer, short BufLen) {
unsigned char* ebx = (unsigned char*) pBuffer; // get a pointer to the top of buffer
unsigned char ecx = ebx[0] + 1; // adjust it up by one
ebx[0] = 0; // now clear the two reserved bytes
ebx[2] = 0;
if(ecx != BufLen) {
printf("Length error in SetModePage %d != %d\n\n", BufLen, (int) ecx);
return 0;
}
char Scsi[6] = {0}; // init the SCSI parameter block
Scsi[0] = SCSI_Cmd_ModeSelect; // set the command
Scsi[1] = 0x10; // set the Page Format bit
@ -339,16 +376,21 @@ void ModifyModePage(char *PageBuff, char ecc, char retries) {
ebx[8] = retries; // then set the write count too
}
void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
long SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
char PageBuff[40];
#ifdef NO_EXCESS_READS
// Limit reads to 20 bytes on Zip to prevent controller errors
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, JazDrive ? sizeof(PageBuff) : 20);
// Limit reads to 20 bytes on Zip (24 bytes on Jaz) to prevent controller errors
const short pageBuffLen = JazDrive ? 24 : 20;
#else
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, sizeof(PageBuff));
const short pageBuffLen = sizeof(PageBuff);
#endif
long eax = GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
if(eax) {
printf("SetErrorRecovery failed\n");
return eax;
}
#define EARLY_RECOVERY 0x08
#define PER 0x04
#define SUPPRESS_ECC 0x01
@ -356,6 +398,9 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
// set the ECC fields
char ecc = SUPPRESS_ECC; // presume ECC suppression
if(ECC) {
#ifdef SUPRESS_ER_ERRORS
if(!SupressEarlyRecovery)
#endif
ecc = EARLY_RECOVERY; // enable ECC and Early Recovery
if(Testing) {
ecc = EARLY_RECOVERY | PER; // we're testing, so EER & PER
@ -370,14 +415,22 @@ void SetErrorRecovery(bool Retries, bool ECC, bool Testing) {
retries = 0;
ModifyModePage(PageBuff, ecc, retries);
const long eax = SetModePage(CurrentDevice, PageBuff);
eax = SetModePage(CurrentDevice, PageBuff, pageBuffLen);
// 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
GetModePage(CurrentDevice, ERROR_RECOVERY_PAGE, PageBuff, pageBuffLen);
ecc &= ~EARLY_RECOVERY; // same, *BUT*NOT* Early Recovery
ModifyModePage(PageBuff, ecc, retries);
SetModePage(CurrentDevice, PageBuff);
eax = SetModePage(CurrentDevice, PageBuff, pageBuffLen);
#ifdef SUPRESS_ER_ERRORS
if(!eax) {
printf(" Early recovery not supported on this drive. Ignoring.\n\n");
SupressEarlyRecovery = true;
}
#endif
}
return eax;
}
/*******************************************************************************
@ -464,7 +517,18 @@ long GetSpareSectorCounts(char checkPassword) {
Scsi[0] = SCSI_Cmd_ReadDefectData;
Scsi[2] = 0x1e; // 0b00011110 defect format, G/P bits
Scsi[8] = 4; // ask for only FOUR bytes
#ifdef SUPPRESS_DEFECTS_ERROR
if(SupressDefectsError)
eax = INCOMPATIBLE_MEDIA;
else
#endif
eax = SCSICommand(CurrentDevice, Scsi, &DefectHeader, sizeof(DefectHeader));
#ifdef SUPPRESS_DEFECTS_ERROR
if(!SupressDefectsError && eax == INCOMPATIBLE_MEDIA) {
printf("Defects list not supported on this drive. Ignoring.\n\n");
SupressDefectsError = true;
}
#endif
if ((!eax) || (eax == INCOMPATIBLE_MEDIA)) {
// we could read its defect list ... so show it!
// --------------------------------------------------------------------------
@ -570,10 +634,11 @@ Rescan:
do {
// clear media changed status
DriveArray[i].flags &= ~MEDIA_CHANGED;
GetCartridgeStatus(scsi_id);
GetCartridgeStatus(scsi_id, DriveArray[i].flags);
} while(DriveArray[i].flags & MEDIA_CHANGED); // do it until NO media change!
//--------------------------------------------------------------------------
status = GetCartridgeStatus(scsi_id);
status = GetCartridgeStatus(scsi_id, DriveArray[i].flags);
if (status == DISK_STATUS_UNKNOWN) continue; // added by MLT
// if the device we have is NOT the currently selected one
if(scsi_id != CurrentDevice) {
// if the disk is ANYTHING other than not present ...
@ -589,6 +654,7 @@ Rescan:
// then set the current drive ...
else if ((DriveArray[i].flags & DISK_EJECTING) == 0) {
CurrentDevice = scsi_id;
printf("Selected SCSI ID %ld\n", CurrentDevice);
TestingPhase = 0;
Selecting = true;
//goto Rescan;
@ -604,13 +670,13 @@ Rescan:
// it is *NOT* empty! If it *IS* empty, kill current
if(status == DISK_NOT_PRESENT) {
CurrentDevice = -1;
SetCartridgeStatusToEAX(status);
SetCartridgeStatusToEAX(status, DriveArray[i].flags);
}
// if it's not already set correctly *and* either
// the cart status is one of the pre-test ones, or
// the NEW status from the cart is NOT "at speed" ...
if((status != CartridgeStatus) && ((CartridgeStatus <= DISK_STALLED) || (status != DISK_AT_SPEED))) {
SetCartridgeStatusToEAX(status);
SetCartridgeStatusToEAX(status, DriveArray[i].flags);
}
}
}
@ -618,18 +684,18 @@ Rescan:
if ((CurrentDevice == -1) &&
(status == DISK_NOT_PRESENT) &&
(CartridgeStatus != DISK_NOT_PRESENT)) {
SetCartridgeStatusToEAX(status);
SetCartridgeStatusToEAX(status, 0);
}
}
//-----------------------------------------------------------------------------
// GET CARTRIDGE STATUS
//-----------------------------------------------------------------------------
uint8_t GetCartridgeStatus(long Device) {
uint8_t GetCartridgeStatus(long Device, uint8_t flags) {
long eax;
char DiskStat[72];
#ifdef NO_EXCESS_READS
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, JazDrive ? sizeof(DiskStat) : 63);
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, 4);
if (eax) return DISK_STATUS_UNKNOWN;
#else
eax = GetNonSenseData(Device, DISK_STATUS_PAGE, DiskStat, sizeof(DiskStat));
@ -646,7 +712,9 @@ uint8_t GetCartridgeStatus(long Device) {
// SetCartridgeStatusToEAX
//-----------------------------------------------------------------------------
void SetCartridgeStatusToEAX(long eax) {
void SetCartridgeStatusToEAX(long eax, uint8_t flags) {
JazDrive = flags & JAZ_DRIVE;
long PriorStatus = CartridgeStatus;
CartridgeStatus = eax;
@ -666,6 +734,7 @@ void SetCartridgeStatusToEAX(long eax) {
SetRichEditText(szNotRunning);
goto DisableActions;
case DISK_AT_SPEED:
printf("Disk at speed\n");
eax = GetSpareSectorCounts(true); // update the Cart Condition
if(eax == MEDIA_NOT_PRESENT) {
goto DisableActions;
@ -678,10 +747,14 @@ void SetCartridgeStatusToEAX(long eax) {
FirmErrors = 0;
// check to see if we have enough spares to start
if(JazDrive) {
printf("Spare Sectors: %ld/%d\n", Side_0_SparesCount, MAXIMUM_JAZ_SPARES);
if(Side_0_SparesCount < MINIMUM_JAZ_SPARES)
goto InsufficientSpares;
}
else {
printf("Spare Sectors:\n");
printf(" Side 1: %ld/%d\n", Side_0_SparesCount, MAXIMUM_ZIP_SPARES);
printf(" Side 2: %ld/%d\n", Side_1_SparesCount, MAXIMUM_ZIP_SPARES);
if(Side_0_SparesCount < MINIMUM_ZIP_SPARES) {
goto InsufficientSpares;
}
@ -753,6 +826,12 @@ void PrepareToBeginTesting() {
HardErrors = 0;
UserInterrupt = 0;
LastError = 0;
#ifdef SUPRESS_ER_ERRORS
SupressEarlyRecovery = false;
#endif
#ifdef SUPPRESS_DEFECTS_ERROR
SupressDefectsError = false;
#endif
#ifdef DEMO
LastLBAOnCartridge = 99999;
SoftErrors = 6;
@ -782,7 +861,7 @@ void BumpErrorCounts(long ErrorCode) {
LastError = eax;
if (eax == 0x320003 || eax == 0x328F03)
CartridgeStatus = DISK_LOW_SPARES;
if (eax & 0xFF == 1) // recovered error
if ((eax & 0xFF) == 1) // recovered error
SoftErrors++;
else
HardErrors++;
@ -812,12 +891,12 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
char Scsi[10] = {0}; // clear out the SCSI CDB
const long InitialHardErrors = HardErrors;
SetErrorRecovery(false, false, true); // disable Retries & ECC
long eax = SetErrorRecovery(false, false, true); // disable Retries & ECC
Scsi[0] = XferCmd;
SET_DWORD_AT(Scsi, 2, MAKE_BIG_ENDIAN(FirstLBASector)); // WHICH LBA's to read, BIG endian
SET_WORD_AT (Scsi, 7, MAKE_BIG_ENDIAN(NumberOfLBAs)); // HOW MANY to read, BIG endian
long eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
eax = SCSICommand(CurrentDevice, Scsi, pBuffer, NumberOfLBAs * BYTES_PER_SECTOR);
// 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!
@ -826,6 +905,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
goto Exit;
}
printf("Starting detailed search...\n");
//--------------------------------------------------------------------------
// 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!
@ -855,6 +936,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
if (eax == SS_ERR) goto Exit; // if it's a CONTROLLER ERROR, skip!
if (eax & 0xFF == 1) goto PostTheError; // did we recover?
printf(" Found error, retesting with retries\n");
SetErrorRecovery(true, false, true); // enable retries
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
if (eax) {
@ -862,7 +944,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
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
printf(" Found error, retesting with retries & ECC\n");
eax = SetErrorRecovery(true, true, true); // enable retries AND EEC
eax = SCSICommand(CurrentDevice, Scsi, LocalBuffer, BYTES_PER_SECTOR);
if (eax) {
// failed with retries and EEC
@ -880,6 +963,8 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
}
PostTheError:
printf(" %s (Sector %ld)\n", FindErrorString(eax), SingleTransferLBA);
printf("--------------------------------------------\n");
BumpErrorCounts(eax); // given eax, count the errors
GetSpareSectorCounts(false); // update the Cart's Condition
UpdateRunTimeDisplay();
@ -889,6 +974,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
ProcessPendingMessages();
}
printf("... detailed search finished\n");
// now see whether we *did* found something to complain about ...
eax = SoftErrors + HardErrors;
if (eax == GlitchCount) {
@ -899,6 +985,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
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"
printf("%s\n", FindErrorString(eax));
BumpErrorCounts(eax); // given eax, count the errors
HardErrors = SavedHardErrors; // restore the counts
SoftErrors = SavedSoftErrors;
@ -909,6 +996,7 @@ long PerformRegionTransfer(short XferCmd, void *pBuffer) {
eax = 0; // now let's return happiness to our caller
if (HardErrors != InitialHardErrors) // UNRECOVERABLE errors!
eax = -1;
printf("\n");
}
Exit:
@ -921,14 +1009,25 @@ Exit:
*******************************************************************************/
void TestTheDisk() {
void *pPatternBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
void *pUserDataBuffer = malloc(MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
// setup the initital maximum tranfer ...
AdapterMaxSectors = MAX_SECTORS_PER_TEST; // limit to our max
if(pPatternBuffer == NULL || pUserDataBuffer == NULL) {
printf("Allocation error\n");
return;
void *pDataBuffer = 0;
for(;;) {
pDataBuffer = malloc(AdapterMaxSectors * BYTES_PER_SECTOR * 2);
if(pDataBuffer) break;
AdapterMaxSectors >>= 2; // we need to make it smaller
if(AdapterMaxSectors == 0) {
printf("Test buffer allocation failed!\n");
return;
}
}
printf("Allocated buffer of %ld bytes\n", AdapterMaxSectors * BYTES_PER_SECTOR);
void *pPatternBuffer = pDataBuffer;
void *pUserDataBuffer = (char*) pDataBuffer + AdapterMaxSectors * BYTES_PER_SECTOR;
StopApplicationTimer();
PreventProgramExit();
@ -939,17 +1038,17 @@ void TestTheDisk() {
InvalidateRect(hTestMonitor);
LockCurrentDrive(); // prevent media removal
GetSpareSectorCounts(false); // update the Cart's Condition
UpdateRunTimeDisplay();
// Standard Testing Operation
StartingInstant = GetSystemTime();
long eax;
do {
ProcessPendingMessages();
NumberOfLBAs = MAX_SECTORS_PER_TEST;
NumberOfLBAs = AdapterMaxSectors;
if(LastLBAOnCartridge) {
if (FirstLBASector + NumberOfLBAs > LastLBAOnCartridge + 1) {
@ -966,7 +1065,7 @@ void TestTheDisk() {
// get a random pattern of data to write
const long DataPattern = rand();
memset(pPatternBuffer, DataPattern, MAX_SECTORS_PER_TEST * BYTES_PER_SECTOR);
memset(pPatternBuffer, DataPattern, AdapterMaxSectors * BYTES_PER_SECTOR);
// update the cartridge's status
GetSpareSectorCounts(false); // update the Cart's Condition
@ -975,7 +1074,7 @@ void TestTheDisk() {
UpdateRunTimeDisplay();
long eax = PerformRegionTransfer(SCSI_Cmd_ReadMany, pUserDataBuffer);
eax = PerformRegionTransfer(SCSI_Cmd_ReadMany, pUserDataBuffer);
if(eax == 0) {
// -------------------------------
@ -995,6 +1094,10 @@ void TestTheDisk() {
// if we hit the end of the disk ... exit gracefully!
goto GetOut;
}
else if (eax == SS_ERR) {
// added by MLT, exit on controller errors
goto GetOut;
}
if (CartridgeStatus != DISK_TEST_UNDERWAY) {
break;
}
@ -1004,8 +1107,7 @@ void TestTheDisk() {
// show that we're post-test
GetOut:
free(pPatternBuffer);
free(pUserDataBuffer);
free(pDataBuffer);
TestingPhase = UNTESTED;
UnlockAllMedia();
@ -1015,24 +1117,24 @@ GetOut:
AllowProgramExit();
// compute the number of serious troubles
const char *eax;
const char *result;
long errors = FirmErrors + HardErrors;
if (errors >= BADNESS_THRESHOLD) {
eax = szBadResult;
result = szBadResult;
}
else if (UserInterrupt) {
eax = szInterrupted;
else if (UserInterrupt || (eax == SS_ERR)) {
result = szInterrupted;
}
else {
// it wasn't interrupted, nor seriously bad, was it perfect?
errors += SoftErrors;
if(errors) {
eax = szExplainResult;
result = szExplainResult;
} else {
eax = szPerfectResult;
result = szPerfectResult;
}
}
SetRichEditText(eax);
SetRichEditText(result);
InvalidateRect(hTestMonitor);
Exit:
StartApplicationTimer();

View File

@ -5,9 +5,11 @@
#include <ctype.h>
#include <SIOUX.h>
#include <Menus.h>
#include <Windows.h>
#include <Quickdraw.h>
#include "TrapAvail.h"
#include "pstring.h"
#include "LaunchLib.h"
#include "mac_vol.h"
@ -15,17 +17,13 @@
#include "tip.h"
#include "command_line.h"
enum TipPage {
kTestingPage,
kExplainPage,
} page;
static int gDone;
static bool allowColor;
static bool inited = false;
static bool timerEnabled = false;
static WindowPtr tipWindow;
static MenuHandle tipMenu;
static PicHandle tipIntroPic;
static TBHandle richText;
static const char *textFileName;
@ -34,13 +32,14 @@ void DisposeTipWindow();
void AddTipMenus();
void RunCommandLine();
void DoEvent(EventRecord &event, RgnHandle *cursorRgn);
void DoMenuEvent(EventRecord &event);
void DoMenuEventPostSIOUX(EventRecord &event);
bool DoMenuSelection(long choice);
void DoUpdate(WindowPtr window);
void DoMouseDown(EventRecord &event);
void DoMouseMove(EventRecord &event, RgnHandle *cursorRegion);
void DoDiskEvent(EventRecord &event);
void SetPage(TipPage page);
ControlHandle FindControl(int id);
ControlHandle FindCntlHandle(int id);
OSErr GetExplanationFSSpec(const char *name, FSSpec *docSpec);
void OpenExplanationInSimpleText();
@ -55,15 +54,13 @@ void run_tip() {
NewTipWindow();
EnableWindow(hTestButton, false);
SetRichEditText(szInstructions);
gDone = false;
do {
EventRecord event;
if (WaitNextEvent(everyEvent, &event, GetCaretTime(), cursorRgn)) {
DoEvent(event, &cursorRgn);
if(!inited && page == kTestingPage) {
printf("Starting tip\n");
if(!inited && CurrentPage == PERFORM_TEST_PAGE) {
// Start TIP as soon as the user dismisses the intro screen
inited = true;
uint8_t drivesSkipped;
@ -88,6 +85,9 @@ void run_tip() {
DisposeTipWindow();
DisposeRgn(cursorRgn);
// Remount any drives we may have unmounted
mac_mount_drives();
}
void NewTipWindow() {
@ -128,10 +128,12 @@ void NewTipWindow() {
tipBtns[i].y + tipBtns[i].h - mainWndOrigin.v
);
StrToPascal(title, tipBtns[i].name);
tipBtns[i].hndl = NewControl(tipWindow, &rect, title, false, 0, 0, 0, 0, tipBtns[i].id);
tipBtns[i].hndl = NewControl(tipWindow, &rect, title, false, 0, 0, 1, tipBtns[i].type, tipBtns[i].id);
}
page = kExplainPage;
SetControlValue(FindCntlHandle(IDB_BEEP),1); // Check the sound control
CurrentPage = EXPLAIN_RESULTS;
GetDC(hExplainWnd);
// Create the text edit widget
@ -140,10 +142,20 @@ void NewTipWindow() {
ReleaseDC(hExplainWnd);
SetPage(kTestingPage);
// Load the About box picture
tipIntroPic = GetPicture(128);
SetPage(INTRO_PAGE);
}
void AddTipMenus() {
if(!TrapAvailable(0xAA66)) {
// If MenuChoice is available, we can let SIOUX handle the menus,
// otherwise we have to handle it ourselves
SIOUXSettings.setupmenus = FALSE;
}
// Add our menu
tipMenu = GetMenu(128);
InsertMenu(tipMenu, 0);
DrawMenuBar();
@ -166,7 +178,7 @@ void DisposeTipWindow() {
DisposeWindow(tipWindow);
}
ControlHandle FindControl(int id) {
ControlHandle FindCntlHandle(int id) {
for(int i = 0; tipBtns[i].name; i++) {
if (tipBtns[i].id == id)
return tipBtns[i].hndl;
@ -177,11 +189,14 @@ ControlHandle FindControl(int id) {
bool PrepareDC(int which) {
SetPort(tipWindow);
switch(which) {
case hIntroWnd:
if(CurrentPage != INTRO_PAGE) return false;
break;
case hExplainWnd:
if(page != kExplainPage) return false;
if(CurrentPage != EXPLAIN_RESULTS) return false;
break;
case hTestMonitor:
if(page != kTestingPage) return false;
if(CurrentPage != PERFORM_TEST_PAGE) return false;
SetOrigin(-20, -10);
break;
case hMainWnd:
@ -204,36 +219,54 @@ void DoEvent(EventRecord &event, RgnHandle *cursorRgn) {
case osEvt: DoMouseMove(event, cursorRgn); break;
}
} else { // Trap unhandled SIOUX menu events
DoMenuEvent(event);
DoMenuEventPostSIOUX(event);
}
}
void DoMenuEvent(EventRecord &event) {
// SIOUX will handle the menu event, but we can check after the fact
// to see whether the user selected one of our menus
void DoMenuEventPostSIOUX(EventRecord &event) {
if(!SIOUXSettings.setupmenus) return;
/* If MenuChoice is available, it is best to let SIOUX handle the menu
* event so Copy and Paste will work. We can check after the fact
* to see whether the user selected one of our menus using MenuChoice.
* However, if that trap is not available, we must handle the menu
* ourselves and certain menu items will not work
*/
WindowPtr thisWindow;
if(event.what == mouseDown && FindWindow(event.where, &thisWindow) == inMenuBar) {
long int choice = MenuChoice();
int menuId = HiWord(choice);
int itemId = LoWord(choice);
switch(menuId) {
case 32000: // Apple menu
SysBeep(10);
break;
case 32001: // File menu
if (itemId == 9) {
WndProc(WM_COMMAND, IDB_QUIT);
}
break;
case 32002: // Edit menu
case 128: // TIP menu
switch(itemId) {
case 1: HiliteMenu(0); RunCommandLine(); break;
}
}
if((event.what == mouseDown) && (FindWindow(event.where, &thisWindow) == inMenuBar)) {
DoMenuSelection(MenuChoice());
}
}
bool DoMenuSelection(long choice) {
bool handled = false;
int menuId = HiWord(choice);
int itemId = LoWord(choice);
//printf("Menu choice: %d, %d\n", menuId, itemId);
switch(menuId) {
case 32000: // Apple menu SysBeep(10);
break;
case 32001: // File menu
if (itemId == 9) { // Quit
WndProc(WM_COMMAND, IDB_QUIT);
handled = true;
}
break;
case 32002: // Edit menu
break;
case 128: // TIP menu
switch(itemId) {
case 1: // Run Command Line...
HiliteMenu(0);
RunCommandLine();
handled = true;
break;
}
break;
}
HiliteMenu(0);
return handled;
}
void DoUpdate(WindowPtr window) {
@ -257,6 +290,7 @@ void DoUpdate(WindowPtr window) {
DrawEdge(&(*richText)->frame, BDR_SUNKENOUTER, BF_RECT);
ReleaseDC(hExplainWnd);
SetColor(BLACK_COLOR);
UpdateControls(window, window->visRgn);
EndUpdate(window);
@ -280,22 +314,32 @@ void DoMouseDown(EventRecord &event) {
GetPort(&oldPort);
SetPort(thisWindow);
GlobalToLocal(&mouse);
const bool hitButton = (!TBMouseDown(richText, mouse, thisWindow)) &&
(FindControl(mouse, thisWindow, &thisControl) == inButton) &&
(TrackControl(thisControl, mouse, 0) == inButton);
int part;
const bool hitCntl = (!TBMouseDown(richText, mouse, thisWindow)) &&
(FindControl(mouse, thisWindow, &thisControl)) &&
(part = TrackControl(thisControl, mouse, 0));
SetPort(oldPort);
if(hitButton) {
if(hitCntl && (part == inButton) || (part == inCheckBox)) {
int id = GetControlReference(thisControl);
switch(id) {
case IDB_OKAY:
SetPage(kTestingPage);
SetPage(PERFORM_TEST_PAGE);
break;
case IDB_EXPL:
SetPage(kExplainPage);
SetPage(EXPLAIN_RESULTS);
break;
case IDB_NEXT:
SetRichEditText(szInstructions);
break;
case IDB_READ:
OpenExplanationInSimpleText();
break;
case IDB_BEEP:
SetPort(thisWindow);
SetControlValue(thisControl, 1 - GetControlValue(thisControl));
SetPort(oldPort);
printf("Value: %d\n", GetControlValue(thisControl));
break;
default:
WndProc(WM_COMMAND, id);
break;
@ -311,6 +355,14 @@ void DoMouseDown(EventRecord &event) {
gDone = true;
}
break;
case inMenuBar:
if(!DoMenuSelection(MenuSelect(event.where))) {
SysBeep(10);
}
break;
case inDrag:
DragWindow(thisWindow, event.where, &(*GetGrayRgn())->rgnBBox);
break;
}
}
@ -358,10 +410,21 @@ void StrToPascal(Str255 pStr, const char *str) {
}
void SetPage(TipPage newPage) {
if(page == newPage) return;
page = newPage;
switch(page) {
case kTestingPage:
if(CurrentPage == newPage) return;
CurrentPage = newPage;
switch(CurrentPage) {
case INTRO_PAGE:
ShowWindow(IDB_TEST, SW_HIDE);
ShowWindow(IDB_BACK, SW_HIDE);
ShowWindow(IDB_EXPL, SW_HIDE);
ShowWindow(IDB_BEEP, SW_HIDE);
ShowWindow(IDB_OKAY, SW_HIDE);
ShowWindow(IDB_READ, SW_HIDE);
ShowWindow((*richText)->scroll, SW_HIDE);
ShowWindow(IDB_QUIT, SW_SHOW);
ShowWindow(IDB_NEXT, SW_SHOW);
break;
case PERFORM_TEST_PAGE:
ShowWindow((*richText)->scroll, SW_HIDE);
ShowWindow(IDB_BACK, SW_HIDE);
ShowWindow(IDB_NEXT, SW_HIDE);
@ -370,13 +433,15 @@ void SetPage(TipPage newPage) {
ShowWindow(IDB_TEST, SW_SHOW);
ShowWindow(IDB_EXPL, SW_SHOW);
ShowWindow(IDB_QUIT, SW_SHOW);
ShowWindow(IDB_BEEP, SW_SHOW);
break;
case kExplainPage:
case EXPLAIN_RESULTS:
ShowWindow(IDB_TEST, SW_HIDE);
ShowWindow(IDB_BACK, SW_HIDE);
ShowWindow(IDB_NEXT, SW_HIDE);
ShowWindow(IDB_EXPL, SW_HIDE);
ShowWindow(IDB_QUIT, SW_HIDE);
ShowWindow(IDB_BEEP, SW_HIDE);
ShowWindow(IDB_OKAY, SW_SHOW);
ShowWindow(IDB_READ, SW_SHOW);
ShowWindow((*richText)->scroll, SW_SHOW);
@ -478,10 +543,10 @@ void SetRichEditText(const char *name) {
// Load the text from the file
TBReadSimpleText(richText, &docSpec);
TBReadSimpleText(richText, &docSpec, false);
if (name != szRunning && name != szNotRunning) {
SetPage(kExplainPage);
SetPage(EXPLAIN_RESULTS);
} else {
InvalidateRect(hDefault);
}
@ -666,7 +731,7 @@ unsigned long GetSystemTime() {
void SetWindowText(int id, const char *str) {
Str255 pStr;
StrToPascal(pStr, str);
ControlHandle hCntl = FindControl(id);
ControlHandle hCntl = FindCntlHandle(id);
if(hCntl) {
GetDC(hDefault);
SetCTitle(hCntl, pStr);
@ -678,7 +743,7 @@ void SetWindowText(int id, const char *str) {
* ENABLE WINDOW
*******************************************************************************/
void EnableWindow(int id, bool enabled) {
ControlHandle hCntl = FindControl(id);
ControlHandle hCntl = FindCntlHandle(id);
if(hCntl) {
GetDC(hDefault);
HiliteControl(hCntl, enabled ? 0 : 255);
@ -696,7 +761,7 @@ void ShowWindow(ControlHandle hCntl, int state) {
}
void ShowWindow(int id, int state) {
ControlHandle hCntl = FindControl(id);
ControlHandle hCntl = FindCntlHandle(id);
if(hCntl) {
GetDC(hDefault);
ShowWindow(hCntl, state);
@ -704,6 +769,19 @@ void ShowWindow(int id, int state) {
}
}
/*******************************************************************************
* SEND MESSAGE
*******************************************************************************/
long SendMessage(int id, int msg) {
if(msg == BM_GETCHECK) {
ControlHandle hCntl = FindCntlHandle(id);
if(hCntl) {
return GetControlValue(hCntl) ? BST_CHECKED: 0;
}
}
return 0;
}
/*******************************************************************************
* INVALIDATE RECT
*******************************************************************************/
@ -744,3 +822,17 @@ void ProcessPendingMessages() {
}
SystemTask();
}
/*******************************************************************************
* SPLASH THE BITMAP
*******************************************************************************/
void SplashTheBitmap() {
GetDC(hIntroWnd);
Rect rect;
SetRect(&rect, 16, 18, 16+120, 18/*+258*/ +220);
if(tipIntroPic) {
DrawPicture(tipIntroPic, &rect);
}
DrawEdge(&rect, BDR_SUNKENOUTER, BF_RECT);
ReleaseDC(hIntroWnd);
}

View File

@ -123,11 +123,36 @@ ErrorTypeList errorTypeList[] = {
0x0088020B, "Side Switch Error",
0x00FFFFE6, "Buffer Too Big",
/***** Mac SCSI Manager Errors *****/
0x00FFFF02, "SCSI comm err, timeout",
0x00FFFF03, "SCSI bus arb, timeout",
0x00FFFF05, "SCSI phase error",
0x00FFFF07, "SCSI Manager busy",
0x00FFFF08, "SCSI sequence error",
0x00FFFF09, "SCSI blind, timeout",
0x00FFFF0A, "SCSI compl, phase err",
/***********************************/
0xFFFFFFFF, "-- Unknown Error --",
0, 0
};
/********** Main Window Controls Text ************/
const char *szIntroTitle = "Trouble in Paradise";
const char *szIntroSubTitle = "FREEWARE by Steve Gibson\r" \
"Gibson Research Corporation\r" \
"http://grc.com ( v 2.1b )\r" \
"http://github.com/marciot/mac-tip";
const char *szIntroText =
"A Macintosh port of \"TIP\" for Windows by Marcio Teixeira, made possible by a "
"generous code donation by Steve Gibson.\r\r"
"This freeware utility determines whether an Iomega Zip or Jaz drive is prone "
"to developing the dreaded \"Click of Death\" syndrome. Gibson's "
"research into the maintenance, repair and data recovery of Iomega's removable "
"media mass storage products led to this capability.";
/****************** Control Text *****************/
const char *szBack = "< Back";
@ -162,7 +187,33 @@ TextList TestGrayText[] = {
{155, 39, "Testing Progress"},
{129, 77, "Spare Sectors Consumed"},
{61, 135, "Testing Location"},
/*{219, 135, "Sound"},*/
{219, 135, "Sound"},
{297, 135, "Error Summary"},
{0,0,0}
};
// ----------------------- 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);
BtnList tipBtns[] = {
{IDB_BACK, szBack, 157, 301, 80, 24},
{IDB_NEXT, szNext, 236, 301, 80, 24},
{IDB_QUIT, szQuit, 402, 301, 45, 24},
{IDB_BEEP, "", 252, 211, 22, 22, checkBoxProc},
// For Mac TIP only
{IDB_TEST, szPressToStart, 157, 301, 150, 24},
{IDB_EXPL, "Explain", 330, 301, 60, 24},
{IDB_OKAY, "Okay", 380, 301, 65, 24},
{IDB_READ, "Open in SimpleText...", 210, 301, 160, 24},
{0, 0, 0, 0, 0, 0}
};

View File

@ -1,16 +1,19 @@
/************************************************************
pstring.c
AUTHOR: Marcio Luis Teixeira
CREATED: 9/17/94
LAST REVISION: 11/25/21
(c) 1994-1995 by Marcio Luis Teixeira.
All rights reserved.
*************************************************************/
/****************************************************************************
* Common Libraries (c) 1994 Marcio Teixeira *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* To view a copy of the GNU General Public License, go to the following *
* location: <http://www.gnu.org/licenses/>. *
****************************************************************************/
#include "pstring.h"
#include <ctype.h>

View File

@ -1,16 +1,19 @@
/************************************************************
pstring.h
AUTHOR: Marcio Luis Teixeira
CREATED: 9/17/94
LAST REVISION: 11/25/21
(c) 1994-1995 by Marcio Luis Teixeira.
All rights reserved.
*************************************************************/
/****************************************************************************
* Common Libraries (c) 1994 Marcio Teixeira *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* To view a copy of the GNU General Public License, go to the following *
* location: <http://www.gnu.org/licenses/>. *
****************************************************************************/
short pstrlen( unsigned char *str );
void psetlen( unsigned char *str, short len );