🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Thread View: comp.lang.modula2
5 messages
5 total messages Started by Chris Austin Thu, 01 Feb 1996 12:57
Reading Floppies.
#3220
Author: Chris Austin
Date: Thu, 01 Feb 1996 12:57
12 lines
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.
#3226
Author: "Mark Morgan Lloyd "
Date: Thu, 01 Feb 1996 21:55
21 lines
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.
#3242
Author: Dale Pontius
Date: Fri, 02 Feb 1996 13:11
34 lines
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.
#3244
Author: Joachim Michely
Date: Fri, 02 Feb 1996 22:11
292 lines
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.
#3249
Author: Torbjørn Sund
Date: Tue, 06 Feb 1996 11:12
154 lines
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