Thread View: comp.lang.modula2
5 messages
5 total messages
Started by Chris Austin
Thu, 01 Feb 1996 12:57
Reading Floppies.
Author: Chris Austin
Date: Thu, 01 Feb 1996 12:57
Date: Thu, 01 Feb 1996 12:57
12 lines
835 bytes
835 bytes
In modula-2 is there any way that you can determine whether a floppy drive currently contains a disk and whether it is correctly formatted, (i.e. whether the drive is readable), without getting the DOS abort, retry or ignore message. I would like this to work with CD's, IOMEGA ZipDrives, etc... as well. I have looked through a list of interrupts, but am unable to find one to do this. I am able to tell whether the drive exists, by using the setdrive & getdrive interrupts. Any help would be appreciated. Chris
Re: Reading Floppies.
Author: "Mark Morgan Lloyd "
Date: Thu, 01 Feb 1996 21:55
Date: Thu, 01 Feb 1996 21:55
21 lines
1453 bytes
1453 bytes
What operating system are you running under? What compiler are you hoping to use? If you are hoping to support such a wide range of devices you will have substantial problems (I speak from experience here) and under DOS may find it most practical to hook INT 24H- if you refer to appropriate technical info you will find that there is a technique to return straight to the application with an error code. I can warn you however, that you will be getting into _very_ deep water here- the code is not at all simple, cannot be expressed in a high-level language (i.e. you will need inline assembler and an intimate (I'm tempted to say gynaecological) knowledge of the stack state) and may vary depending on the memory model in use, and I admit freely that I do not know what would happen if you attempted to run under Windows 3.x, Windows '95, Windows NT, OS/2, or a DOS emulator such as DOS Merge. You may find it easier to educate your users. :-) Mark Morgan Lloyd mark_tbu@cix.compulink.co.uk [Opinions above are the author's, not those of his employers or colleagues]
Re: Reading Floppies.
Author: Dale Pontius
Date: Fri, 02 Feb 1996 13:11
Date: Fri, 02 Feb 1996 13:11
34 lines
2132 bytes
2132 bytes
In article <1996Feb1.125721.18589@ucl.ac.uk>, zcaccau@cs.ucl.ac.uk (Chris Austin) writes: > In modula-2 is there any way that you can determine whether a floppy drive > currently contains a disk and whether it is correctly formatted, (i.e. > whether the drive is readable), without getting the DOS abort, retry or > ignore message. I would like this to work with CD's, IOMEGA ZipDrives, > etc... as well. I have looked through a list of interrupts, but am unable > to find one to do this. I am able to tell whether the drive exists, by > using the setdrive & getdrive interrupts. > > Any help would be appreciated. To expand on the two other responses, (and I hope I'm not talking down to you here) Int24 is the DOS Critical Error Handler. It isn't handled quite like other interrupts, and it isn't exited quite like other interrupts. It probably is the best way for you to go, and as someone said, the JPI compiler includes a sample Int24 handler. I'm not sure if you can call it from inside the Int24 handler, or if you have to wait (probably) until the Int24 handler and the failed DOS call return, but there is another call (I forget the number) that will return extended fail information. This may help you get more of what you need to know, as well. I once used the JPI sample Int24 handler as my starting point for a TSR, since it showed how to completely capture registers on call, and with minor changes could switch to its own stack. Someone offered to email this code to you. Watch out, it has a JPI copyright. Especially if you want to ship/sell something based on it you should acquire a legitimate copy. (I think it's in the Tech-Kit) Dale Pontius (NOT speaking for IBM)
Re: Reading Floppies.
Author: Joachim Michely
Date: Fri, 02 Feb 1996 22:11
Date: Fri, 02 Feb 1996 22:11
292 lines
9367 bytes
9367 bytes
zcaccau@cs.ucl.ac.uk writes in article <1996Feb1.125721.18589@ucl.ac.uk>:
>
>
> In modula-2 is there any way that you can determine whether a floppy drive
> currently contains a disk and whether it is correctly formatted, (i.e.
> whether the drive is readable), without getting the DOS abort, retry or
> ignore message. I would like this to work with CD's, IOMEGA ZipDrives,
> etc... as well. I have looked through a list of interrupts, but am unable
> to find one to do this. I am able to tell whether the drive exists, by
> using the setdrive & getdrive interrupts.
This has nothing special to do with Modula, its DOS.
You have to use DOS Interrupts and write an "Critical Error Handler-Int 24h"
to intercept the error code. You can analyse the received error code in
the Int24 Handler. You will receive information about the device - block
( eg. Diskette or Disk ) or character device ( eg. LPT or COM ) and the type
of operation involved ( eg. read, write ). You can transfer information back
of what to do ( eg. RETRY, ABORT, FAIL, IGNORE ) to DOS.
I use it in my own programs.
The following code is for Logitech Modula Vers 3.4. The Multiscope Vers 4.0
compiler needs some changes because identifier names have changed a little
and moved to other modules. But it should be no problem ( Multiscope Vers 4.0
is the Stonybrook compiler with slightly modified Librarys )
DEFINITION MODULE Int24 ;
TYPE
ContCode = ( ignore , retry , abort , fail ) ;
DiskOp = ( read , write ) ;
DiskPart = ( dos , fat , dir , data ) ;
DeviceName = ARRAY [ 0 .. 7 ] OF CHAR ;
DeviceType = ( block , char ) ;
Int24Error = ( WriteProtect , UnknownUnit , DriveNotReady ,
UnknownCommand , DataError ,
BadRequestStructureLen , SeekError ,
UnknownMedium , SectorNotFound ,
PrinterOutOfPaper , WriteFault , ReadFault ,
GeneralFailure ) ;
ErrorInfo = RECORD
devname : DeviceName ;
CASE devtype : DeviceType OF
block : diskop : DiskOp ;
diskloc : DiskPart ;
| char :
END (* CASE *)
END ; (* RECORD *)
Int24Proc = PROCEDURE ( ErrorInfo , Int24Error ) : ContCode ;
PROCEDURE StartInt24 ( errorproc : Int24Proc ) ;
PROCEDURE StopInt24 ;
END Int24 .
IMPLEMENTATION MODULE Int24 ;
FROM SYSTEM IMPORT
SI,BP,
NEWPROCESS , TRANSFER , IOTRANSFER ,
PROCESS , ADDRESS ,
WORD , BYTE , ADR , SIZE ;
FROM RTSMain IMPORT
ProcessDescriptor ;
FROM Devices IMPORT
InstallHandler ,
SaveInterruptVector ,
RestoreInterruptVector ;
CONST
Int24 = 24H ;
TYPE
DeviceBlock = RECORD
notusedbyus0 : ADDRESS ;
notusedbyus1 : BITSET ;
notusedbyus2 : WORD ;
notusedbyus3 : WORD ;
devicename : DeviceName ;
END ;
ProcessPointer = RECORD
CASE BOOLEAN OF
TRUE : Process : PROCESS ;
| FALSE : Point : POINTER TO ProcessDescriptor ;
END ;
END ;
VAR
active : BOOLEAN ;
OldVector : ADDRESS ;
WorkSpace : ARRAY [ 0 .. 1000 ] OF BYTE ;
IntProc : Int24Proc ;
Int24Process : PROCESS ;
Main : ProcessPointer ;
PROCEDURE StartInt24 ( errorproc : Int24Proc ) ;
BEGIN
IF NOT active THEN
IntProc := errorproc ;
SaveInterruptVector ( Int24 , OldVector ) ;
active := TRUE ;
NEWPROCESS ( Int24Service , ADR ( WorkSpace ) ,
SIZE ( WorkSpace ) , Int24Process ) ;
TRANSFER ( Main.Process , Int24Process ) ;
END ;
END StartInt24 ;
PROCEDURE StopInt24 ;
BEGIN
(*** this functions doesn't work until now.
subsequent StartInt24 and StopInt24 will
lead to an abort of the programm with the
message : ===> too many concurrent I/O processes
but is no problem : never need to call Start/Stop several times
jm 20-feb-90
***)
IF active THEN
active := FALSE ;
RestoreInterruptVector ( Int24 , OldVector ) ;
END ;
END StopInt24 ;
PROCEDURE Int24Service ;
VAR
workset : BITSET ;
info : ErrorInfo ;
work : RECORD
CASE BOOLEAN OF
TRUE : adr : ADDRESS ;
| FALSE : point : POINTER TO DeviceBlock
END ;
END ;
BEGIN
InstallHandler ( Int24Process , Int24 ) ;
LOOP
IOTRANSFER ( Int24Process , Main.Process , Int24 ) ;
workset := BITSET ( Main.Point^.topStack^.AX ) ;
WITH Main.Point^ DO
work.adr.OFFSET := SI ;
work.adr.SEGMENT := BP ;
END ;
WITH info DO
IF 15 IN workset THEN
devtype := char ;
devname := work.point^.devicename ;
ELSE
devtype := block ;
devname := ' (DISK)' ;
devname[0] := CHR ( Main.Point^.topStack^.AX MOD 100H + ORD ( 'A' ) ) ;
IF 8 IN workset THEN
diskop := write ;
ELSE
diskop := read ;
END ;
diskloc := VAL ( DiskPart ,
( Main.Point^.topStack^.AX MOD 800H ) DIV 200H ) ;
END ;
END ; (* WITH *)
WITH Main.Point^.topStack^ DO
AX := ORD ( IntProc ( info , VAL ( Int24Error , DI MOD 10H ) ) ) ;
END ; (* WITH *)
END ; (* LOOP *)
END Int24Service ;
BEGIN
active := FALSE ;
END Int24 .
Example Handler - located in application
FROM Int24 IMPORT
ContCode , DiskPart , DiskOp ,
DeviceType , Int24Error ,
ErrorInfo , StartInt24 ;
PROCEDURE ErrorHandler ( Info : ErrorInfo ; Error : Int24Error ) : ContCode ;
VAR
return : ContCode ;
str : ARRAY [ 0 .. 4 ] OF CHAR ;
BEGIN
Sounds.Sound ( 4000 ) ;
CASE Info.devtype OF
block :
(* 1 1 2 2 3 3 4 4 5 *)
(* 0....5....0....5....0....5....0....5....0....5....0 *)
Cursor ( 10 , 20 ) ;
WriteString ( ' Fehler bei Zugriff auf Diskette ' ) ;
Cursor ( 10 , 21 ) ;
WriteString ( ' Name : ' ) ;
WriteString ( Info.devname ) ;
CASE Info.diskop OF
read : WriteString ( ' during read of ' ) ;
| write : WriteString ( ' during write of ' ) ;
END ;
CASE Info.diskloc OF
dos : WriteString ( ' DOS' ) ;
| fat : WriteString ( ' FAT' ) ;
| dir : WriteString ( ' DIR' ) ;
| data : WriteString ( ' DATA' ) ;
END ;
Cursor ( 10 , 22 ) ;
CASE Error OF
WriteProtect : WriteString ( ' Entferne Schreibschutz' ) ;
| DriveNotReady : WriteString ( ' Lege Diskette ein und Schlieáe Klappe' ) ;
| DataError : WriteString ( ' Schlechte Diskette, probiere andere' ) ;
ELSE
WriteString ( ' Fehler # : ' ) ;
CardToString ( ORD ( Error ) , str , 3 ) ;
WriteString ( str ) ;
END ; (* CASE *)
return := retry ;
| char :
(* 1 1 2 2 3 3 4 4 5 *)
(* 0....5....0....5....0....5....0....5....0....5....0 *)
Cursor ( 10 , 20 ) ;
WriteString ( ' Fehler bei Zugriff auf Printer ' ) ;
WriteString ( ' Name : ' ) ;
Cursor ( 10 , 21 ) ;
WriteString ( Info.devname ) ;
Cursor ( 10 , 22 ) ;
CASE Error OF
DriveNotReady : WriteString ( ' Drucker ausgeschaltet' ) ;
| PrinterOutOfPaper : WriteString ( ' Kein Papier in Drucker' ) ;
| WriteFault : WriteString ( ' Drucker ist nicht bereit' ) ;
ELSE
WriteString ( ' Fehler # : ' ) ;
CardToString ( ORD ( Error ) , str , 3 ) ;
WriteString ( str ) ;
END ; (* CASE *)
return := fail ;
END ; (* CASE devtype OF *)
Delay.Delay ( 1000 ) ;
Sounds.NoSound ;
RETURN return ;
END ErrorHandler ;
In the first lines of the main body write :
StartInt24 ( ErrorHandler ) ;
Cursor and WriteString position the cursor an the screen and write to the
screen. In "ErrorHandler" donït use any DOS Interrupt ( but you can write
to screen ) because DOS isnït reentrant.
This "ErrorHandler" handles not all possible errors, only those I need
in this application.
Any book about DOS programming ( Ray Duncan:Advanced MSDOS .. ) should give
you information about Int24H
Hope this helps
Joachim
>
> Any help would be appreciated.
>
> Chris
>
Joachim Michely, Steinkaule 50, 53757 St-Augustin, Germany
Voice/Fax : ++49-(0)2241-337938 ( and answering machine )
Internet : michely@nemeter.dinoco.DE
CompuServe : 100024,2476
Re: Reading Floppies.
Author: Torbjørn Sund
Date: Tue, 06 Feb 1996 11:12
Date: Tue, 06 Feb 1996 11:12
154 lines
4669 bytes
4669 bytes
In <1996Feb1.125721.18589@ucl.ac.uk>, zcaccau@cs.ucl.ac.uk (Chris Austin) writes:
>
>In modula-2 is there any way that you can determine whether a floppy drive
>currently contains a disk and whether it is correctly formatted, (i.e.
>whether the drive is readable), without getting the DOS abort, retry or
>ignore message. I would like this to work with CD's, IOMEGA ZipDrives,
>etc... as well.
Here's an extract of my low-level BIOS and diskette access code.
All in Modula-2 (sort of), no assembler.
Note I have extracted only relevant portions,
complain to me if I missed something out.
Written for Topspeed M2, but all the non-standard constructs
have similar counterparts in the other DOS compilers.
(and I've seen most under DOS).
The idea of reading from the diskette to detect if it is present
is taken from a fast multitasking diskette copier supplied
in source with the full JPI M2 distribution. The code is mine
so there should be no copyright problems, but credit to
JPI anyway.
Hope this helps.
Cut here:
- - - - - -
DEFINITION MODULE BIOSFun;
CONST
MaxBytesInSector = 1024;
(* following are direct mappings from BIOS functions *)
PROCEDURE ResetDisk( DrvNo: SHORTCARD): SHORTCARD;
PROCEDURE ReadSectors( DrvNo: SHORTCARD;
VAR Buffer: ARRAY OF SHORTCARD; VAR NoSec: SHORTCARD;
HedNo, CylNo, SecNo: SHORTCARD): SHORTCARD;
END BIOSFun.
-- and here --
IMPLEMENTATION MODULE BIOSFun;
(* Interrupt 13H, chosen functions for diskett *)
IMPORT SYSTEM, Lib;
(*%T _XTD *) (* if compiled with extended (protected) memory model *)
IMPORT TSXLIB;
(*%E *)
CONST Int13 = 013H;
(* function 0 *)
PROCEDURE ResetDisk( DrvNo: SHORTCARD): SHORTCARD;
VAR
r: SYSTEM.Registers;
BEGIN
r.AH := 0; r.DL := DrvNo;
Lib.Intr( r, Int13);
RETURN r.AH;
END ResetDisk;
(* function 02 *)
PROCEDURE ReadSectors( DrvNo: SHORTCARD;
VAR Buffer: ARRAY OF SHORTCARD; VAR NoSec: SHORTCARD;
HedNo, CylNo, SecNo: SHORTCARD): SHORTCARD;
VAR
r: SYSTEM.Registers;
BEGIN
WITH r DO
AH := 2;
DL := DrvNo;
AL := NoSec;
CH := CylNo;
CL := SecNo;
DH := HedNo;
ES := Seg(Buffer);
BX := Ofs(Buffer);
Lib.Intr( r, Int13);
NoSec := AL;
RETURN AH;
END;
END ReadSectors;
BEGIN
(*%T _XTD *)
TSXLIB.InitInt13();
(*%E *)
END BIOSFun.
---- and here ----
DEFINITION MODULE Diskett;
(* Utility functions for diskette *)
(* Drive number should be 0 and 1 for A: and B:
if memory serves me right, or maybe it's 1 and 2
*)
PROCEDURE DiskIsPresent( DrvNo: SHORTCARD): BOOLEAN;
PROCEDURE Wait4DiskChange( DrvNo: SHORTCARD);
END Diskett.
--- and here ---
IMPLEMENTATION MODULE Diskett;
IMPORT Lib, BIOSFun;
VAR
DummyBuffer: ARRAY [0 .. BIOSFun.MaxBytesInSector-1] OF SHORTCARD;
PROCEDURE DiskIsPresent( DrvNo: SHORTCARD): BOOLEAN;
VAR
SecCnt,
result : SHORTCARD;
BEGIN
IF BIOSFun.ResetDisk( DrvNo) # 0 THEN RETURN FALSE; END;
SecCnt := 1;
result := BIOSFun.ReadSectors( DrvNo, DummyBuffer, SecCnt, 0, 0, 1);
(* yeah, I know, the result codes below should have been changed
into symbolic constants instead of magic numbers *)
RETURN (result = 0) OR (result = 2) OR (result = 3) OR (result = 4)
OR (result = 6) OR (result = 8) OR (result = 9) OR (result = 10H);
END DiskIsPresent;
PROCEDURE Wait4DiskChange( DrvNo: SHORTCARD);
VAR
SecCnt,
res : SHORTCARD;
BEGIN
(* first wait for diskette to be removed *)
REPEAT
Lib.Delay(750);
SecCnt := 1;
res := BIOSFun.ReadSectors( DrvNo, DummyBuffer, SecCnt, 0, 0, 1);
UNTIL (res=6);
(* then wait until a new one is present *)
WHILE NOT DiskIsPresent( DrvNo) DO Lib.Delay(100); END;
END Wait4DiskChange;
END Diskett.
---------- cut here
Torbjørn Sund Telenor R&D
Tel (+47) 77 61 27 87 Pb 1156, Strandgt 9
Fax (+47) 77 61 27 02 N-9001 Tromsø
torbjorn.sund@fou.telenor.no Norway
Thread Navigation
This is a paginated view of messages in the thread with full content displayed inline.
Messages are displayed in chronological order, with the original post highlighted in green.
Use pagination controls to navigate through all messages in large threads.
Back to All Threads