123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318 |
- (* ported version of Minos to work with the ARM backend of the Fox Compiler Suite *)
- MODULE Device; (* Author: tt, Purpose: Driver Registry *)
- (*@
- This is an abstraction of a character device. Concrete implementations can be found for example for the Uarts and the
- Uart emulation over the avionics IOBoard. Other implementations might be added in the future
-
- 006 2007-07-03 tt: Formatted and added documentation, removed field id
- 005 2006-12-20 tt: Introduced WriteBytes and ReadBytes, adapted the other procedure to use these two procedures,
- Read and Write of Device not blocking, fixed ReadChars, WriteChars
- 004 2006-12-08 fof: added NULL device
- 003 2006-08-09 tt: Now using SYSTEM.BYTE in Read and Write
- 002 2006-08-07 tt: Removed WriteBytesNB
- 001 2006-07-19 tt: Initial Version
- *)
- IMPORT Strings, SYSTEM, UartMin;
- CONST
- (* Maximum length of a device name *)
- DeviceNameLength* = 32;
- TYPE
- DeviceName* = ARRAY DeviceNameLength OF CHAR;
- (* Pointer to a device *)
- Device* = POINTER TO DeviceDesc;
-
- (* A generic driver Plugin that every serial device must implement. All calls are non blocking.*)
- DeviceDesc* = RECORD
- (* Send "len" number of bytes from "buf" starting at offset "ofs". After the call, "len" conatins the number of
- bytes that were sent. This call is non blocking *)
- Write*: PROCEDURE ( dev: Device; CONST buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
- (* Read "len" bytes into "buf" at offset "ofs".
- After the call, "len" contains the number of bytes that have actually been read.
- This call is non blocking *)
- Read*: PROCEDURE ( dev: Device; VAR buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
- (* Returns the number of bytes available in the input buffer *)
- Available*: PROCEDURE ( dev: Device ): LONGINT;
- (* The number of free bytes available in the send buffer *)
- Free*: PROCEDURE ( dev: Device ): LONGINT;
- (* Execute a driver specific command identified by "cmd". "param" is the parameter of the command *)
- Command*: PROCEDURE ( dev: Device; cmd, param: LONGINT; VAR res: LONGINT );
- (* Flush all bytes in the send buffer *)
- Flush*: PROCEDURE ( dev: Device );
- (* Get the textual version of the last occured error *)
- GetErrorText*: PROCEDURE ( dev: Device; VAR err: ARRAY OF CHAR );
- (* Initialise and start this driver *)
- Open*: PROCEDURE ( dev: Device );
- (* Shutdown and disable this driver *)
- Close*: PROCEDURE ( dev: Device );
- (* Result of last operation *)
- res*: LONGINT;
- (* Name of this device. This is used for identification by an application *)
- name*: DeviceName;
- (* Pointer to the next registered driver. This field is not exported, as it is only used by the Registry *)
- next: Device
- END;
- VAR
- (* A linked list of all devices *)
- devices: Device;
-
- (* The NULL device *)
- null: Device;
-
- (* Add a device in the device pool with name "name" and device id "id". The id can be used
- internally for the device *)
- PROCEDURE Install*( device: Device; CONST name: ARRAY OF CHAR );
- BEGIN
- IF device # NIL THEN
- Strings.Copy(name, device.name);
- device.next := devices;
- devices := device
- END
- END Install;
- (* Get the device with name "name". Returns NIL if the device could not be found *)
- PROCEDURE GetDevice*( CONST name: ARRAY OF CHAR ): Device;
- VAR device: Device;
- BEGIN
- device := devices;
- WHILE (device # NIL ) & (device.name # name) DO
- device := device.next
- END;
- RETURN device
- END GetDevice;
- PROCEDURE DumpDevices*;
- VAR
- device: Device;
- BEGIN
- UartMin.StrLn("Device List:");
- device := devices;
- WHILE device # NIL DO
- UartMin.StrLn(device.name);
- device := device.next
- END;
- UartMin.Ln
- END DumpDevices;
- (* Dummy procedures for initialisation *)
- PROCEDURE NullAvailable( dev: Device ): LONGINT;
- BEGIN
- RETURN 0
- END NullAvailable;
- PROCEDURE NullFree( dev: Device ): LONGINT; (* fof: otherwise Log blocks *)
- BEGIN
- RETURN MAX(LONGINT)
- END NullFree;
- PROCEDURE NullWrite( dev: Device; CONST buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
- BEGIN
- (* len := 0; *) (* fof: Write blocks for NULL device *)
- END NullWrite;
- PROCEDURE NullRead( dev: Device; VAR buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
- BEGIN
- len := 0
- END NullRead;
- PROCEDURE NullCommand( dev: Device; cmd, param: LONGINT; VAR res: LONGINT );
- BEGIN
- res := 0;
- END NullCommand;
- PROCEDURE NullProc( dev: Device );
- BEGIN
- END NullProc;
- PROCEDURE NullGetErrorText( dev: Device; VAR err: ARRAY OF CHAR );
- BEGIN
- err := "";
- END NullGetErrorText;
- (* Initialise an already allocated device with dummy procedures and initial values for all devices *)
- PROCEDURE InitDevice*( dev: Device );
- BEGIN
- IF dev # NIL THEN
- dev.next := NIL; dev.name[0] := 0X; dev.res := 0;
- dev.Write := NullWrite;
- dev.Read := NullRead;
- dev.Available := NullAvailable;
- dev.Free := NullFree;
- dev.Command := NullCommand;
- dev.Flush := NullProc;
- dev.GetErrorText := NullGetErrorText;
- dev.Open := NullProc;
- dev.Close := NullProc;
- END;
- END InitDevice;
- (* Read a single character chr from the device dev. This call is blocking *)
- PROCEDURE Read*( dev: Device; VAR chr: CHAR );
- VAR
- len: LONGINT;
- BEGIN
- REPEAT len := 1; dev.Read( dev, chr, 0, len ); UNTIL len = 1;
- END Read;
-
- (* Write a single character "chr" to the device "dev". This call is blocking *)
- PROCEDURE Write*( dev: Device; chr: CHAR );
- VAR
- len: LONGINT;
- BEGIN
- REPEAT len := 1; dev.Write( dev, chr, 0, len ) UNTIL len = 1;
- END Write;
- (* Routines to write and read all standard Oberon types. A read an write pair for all types is provided.
- Note that all calls are blocking *)
- PROCEDURE ReadBool*( dev: Device; VAR bool: BOOLEAN );
- VAR
- ch: CHAR;
- BEGIN
- Read( dev, ch ); bool := ch # 0X
- END ReadBool;
- PROCEDURE WriteBool*( dev: Device; x: BOOLEAN );
- VAR
- c: CHAR;
- BEGIN
- IF x THEN
- c := 1X;
- ELSE
- c := 0X;
- END;
- Write( dev, c )
- END WriteBool;
-
- (* Read len bytes from the device dev and store them in buf starting at location offset. This call is blocking *)
- PROCEDURE ReadBytes( dev: Device; VAR buf: ARRAY OF SYSTEM.BYTE; offset, len: LONGINT );
- VAR
- receive: LONGINT;
- BEGIN
- len := offset + len;
- WHILE offset < len DO
- receive := len - offset; dev.Read( dev, buf, offset, receive );
- offset := offset + receive;
- END;
- END ReadBytes;
- (* Write len bytes from the device dev and store them in buf starting at location offset. This call is blocking *)
- PROCEDURE WriteBytes*( dev: Device; CONST buf: ARRAY OF SYSTEM.BYTE; offset, len: LONGINT );
- VAR
- toSend: LONGINT;
- BEGIN
- len := offset + len;
- WHILE offset < len DO
- toSend := len - offset; dev.Write( dev, buf, offset, toSend );
- offset := offset + toSend;
- END;
- END WriteBytes;
- PROCEDURE ReadChars*( dev: Device; VAR buf: ARRAY OF CHAR; offset, len: LONGINT );
- BEGIN
- ReadBytes( dev, buf, offset, len );
- END ReadChars;
- PROCEDURE WriteChars*( dev: Device; CONST buf: ARRAY OF CHAR; offset, len: LONGINT );
- BEGIN
- WriteBytes( dev, buf, offset, len );
- END WriteChars;
- PROCEDURE ReadInt*( dev: Device; VAR int: LONGINT );
- BEGIN
- ReadBytes( dev, int, 0, 4 );
- END ReadInt;
- PROCEDURE WriteInt*( dev: Device; int: LONGINT );
- BEGIN
- WriteBytes( dev, int, 0, 4 );
- END WriteInt;
- PROCEDURE ReadReal*( dev: Device; VAR real: REAL );
- BEGIN
- ReadBytes( dev, real, 0, 4 );
- END ReadReal;
- PROCEDURE WriteReal*( dev: Device; real: REAL );
- BEGIN
- WriteBytes( dev, real, 0, 4 );
- END WriteReal;
- PROCEDURE ReadSet*( dev: Device; VAR set: SET );
- BEGIN
- ReadBytes( dev, set, 0, 4 );
- END ReadSet;
- PROCEDURE WriteSet*( dev: Device; set: SET );
- BEGIN
- WriteBytes( dev, set, 0, 4 );
- END WriteSet;
- PROCEDURE ReadStr*( dev: Device; VAR buf: ARRAY OF CHAR );
- VAR i: LONGINT; ch: CHAR;
- BEGIN
- i := 0;
- REPEAT Read( dev, ch ); buf[i] := ch; INC( i ) UNTIL ((ch = 0X) OR (i >= LEN( buf )));
- buf[i - 1] := 0X;
- END ReadStr;
- PROCEDURE WriteStr*( dev: Device; CONST buf: ARRAY OF CHAR );
- VAR len: LONGINT;
- BEGIN
- len := 0;
-
- WHILE (len < LEN( buf ) - 1) & (buf[len] # 0X) DO INC( len );
- END;
- INC( len ); WriteChars( dev, buf, 0, len );
- END WriteStr;
-
- (* Just here to make the interface consistent *)
- PROCEDURE Available*( dev: Device ): LONGINT;
- BEGIN
- RETURN dev.Available( dev )
- END Available;
- (* Just here to make the interface consistent *)
- PROCEDURE Free*( dev: Device ): LONGINT;
- BEGIN
- RETURN dev.Free( dev )
- END Free;
- (* Just here to make the interface consistent *)
- PROCEDURE Flush*( dev: Device );
- BEGIN
- dev.Flush( dev )
- END Flush;
- (* Just here to make the interface consistent *)
- PROCEDURE Open*( dev: Device );
- BEGIN
- dev.Open( dev )
- END Open;
- (* Just here to make the interface consistent *)
- PROCEDURE Close*( dev: Device );
- BEGIN
- dev.Close( dev )
- END Close;
- (* Just here to make the interface consistent *)
- PROCEDURE Command*( dev: Device; cmd, param: LONGINT; VAR res: LONGINT );
- BEGIN
- dev.Command( dev, cmd, param, res );
- END Command;
- BEGIN
- devices := NIL;
- NEW( null );
- InitDevice( null ); Install( null, "NULL" );
-
- END Device.
- Device.DumpDevices
|