Device.Mos 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. (* ported version of Minos to work with the ARM backend of the Fox Compiler Suite *)
  2. MODULE Device; (* Author: tt, Purpose: Driver Registry *)
  3. (*@
  4. This is an abstraction of a character device. Concrete implementations can be found for example for the Uarts and the
  5. Uart emulation over the avionics IOBoard. Other implementations might be added in the future
  6. 006 2007-07-03 tt: Formatted and added documentation, removed field id
  7. 005 2006-12-20 tt: Introduced WriteBytes and ReadBytes, adapted the other procedure to use these two procedures,
  8. Read and Write of Device not blocking, fixed ReadChars, WriteChars
  9. 004 2006-12-08 fof: added NULL device
  10. 003 2006-08-09 tt: Now using SYSTEM.BYTE in Read and Write
  11. 002 2006-08-07 tt: Removed WriteBytesNB
  12. 001 2006-07-19 tt: Initial Version
  13. *)
  14. IMPORT Strings, SYSTEM, UartMin;
  15. CONST
  16. (* Maximum length of a device name *)
  17. DeviceNameLength* = 32;
  18. TYPE
  19. DeviceName* = ARRAY DeviceNameLength OF CHAR;
  20. (* Pointer to a device *)
  21. Device* = POINTER TO DeviceDesc;
  22. (* A generic driver Plugin that every serial device must implement. All calls are non blocking.*)
  23. DeviceDesc* = RECORD
  24. (* Send "len" number of bytes from "buf" starting at offset "ofs". After the call, "len" conatins the number of
  25. bytes that were sent. This call is non blocking *)
  26. Write*: PROCEDURE ( dev: Device; CONST buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
  27. (* Read "len" bytes into "buf" at offset "ofs".
  28. After the call, "len" contains the number of bytes that have actually been read.
  29. This call is non blocking *)
  30. Read*: PROCEDURE ( dev: Device; VAR buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
  31. (* Returns the number of bytes available in the input buffer *)
  32. Available*: PROCEDURE ( dev: Device ): LONGINT;
  33. (* The number of free bytes available in the send buffer *)
  34. Free*: PROCEDURE ( dev: Device ): LONGINT;
  35. (* Execute a driver specific command identified by "cmd". "param" is the parameter of the command *)
  36. Command*: PROCEDURE ( dev: Device; cmd, param: LONGINT; VAR res: LONGINT );
  37. (* Flush all bytes in the send buffer *)
  38. Flush*: PROCEDURE ( dev: Device );
  39. (* Get the textual version of the last occured error *)
  40. GetErrorText*: PROCEDURE ( dev: Device; VAR err: ARRAY OF CHAR );
  41. (* Initialise and start this driver *)
  42. Open*: PROCEDURE ( dev: Device );
  43. (* Shutdown and disable this driver *)
  44. Close*: PROCEDURE ( dev: Device );
  45. (* Result of last operation *)
  46. res*: LONGINT;
  47. (* Name of this device. This is used for identification by an application *)
  48. name*: DeviceName;
  49. (* Pointer to the next registered driver. This field is not exported, as it is only used by the Registry *)
  50. next: Device
  51. END;
  52. VAR
  53. (* A linked list of all devices *)
  54. devices: Device;
  55. (* The NULL device *)
  56. null: Device;
  57. (* Add a device in the device pool with name "name" and device id "id". The id can be used
  58. internally for the device *)
  59. PROCEDURE Install*( device: Device; CONST name: ARRAY OF CHAR );
  60. BEGIN
  61. IF device # NIL THEN
  62. Strings.Copy(name, device.name);
  63. device.next := devices;
  64. devices := device
  65. END
  66. END Install;
  67. (* Get the device with name "name". Returns NIL if the device could not be found *)
  68. PROCEDURE GetDevice*( CONST name: ARRAY OF CHAR ): Device;
  69. VAR device: Device;
  70. BEGIN
  71. device := devices;
  72. WHILE (device # NIL ) & (device.name # name) DO
  73. device := device.next
  74. END;
  75. RETURN device
  76. END GetDevice;
  77. PROCEDURE DumpDevices*;
  78. VAR
  79. device: Device;
  80. BEGIN
  81. UartMin.StrLn("Device List:");
  82. device := devices;
  83. WHILE device # NIL DO
  84. UartMin.StrLn(device.name);
  85. device := device.next
  86. END;
  87. UartMin.Ln
  88. END DumpDevices;
  89. (* Dummy procedures for initialisation *)
  90. PROCEDURE NullAvailable( dev: Device ): LONGINT;
  91. BEGIN
  92. RETURN 0
  93. END NullAvailable;
  94. PROCEDURE NullFree( dev: Device ): LONGINT; (* fof: otherwise Log blocks *)
  95. BEGIN
  96. RETURN MAX(LONGINT)
  97. END NullFree;
  98. PROCEDURE NullWrite( dev: Device; CONST buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
  99. BEGIN
  100. (* len := 0; *) (* fof: Write blocks for NULL device *)
  101. END NullWrite;
  102. PROCEDURE NullRead( dev: Device; VAR buf: ARRAY OF SYSTEM.BYTE; ofs: LONGINT; VAR len: LONGINT );
  103. BEGIN
  104. len := 0
  105. END NullRead;
  106. PROCEDURE NullCommand( dev: Device; cmd, param: LONGINT; VAR res: LONGINT );
  107. BEGIN
  108. res := 0;
  109. END NullCommand;
  110. PROCEDURE NullProc( dev: Device );
  111. BEGIN
  112. END NullProc;
  113. PROCEDURE NullGetErrorText( dev: Device; VAR err: ARRAY OF CHAR );
  114. BEGIN
  115. err := "";
  116. END NullGetErrorText;
  117. (* Initialise an already allocated device with dummy procedures and initial values for all devices *)
  118. PROCEDURE InitDevice*( dev: Device );
  119. BEGIN
  120. IF dev # NIL THEN
  121. dev.next := NIL; dev.name[0] := 0X; dev.res := 0;
  122. dev.Write := NullWrite;
  123. dev.Read := NullRead;
  124. dev.Available := NullAvailable;
  125. dev.Free := NullFree;
  126. dev.Command := NullCommand;
  127. dev.Flush := NullProc;
  128. dev.GetErrorText := NullGetErrorText;
  129. dev.Open := NullProc;
  130. dev.Close := NullProc;
  131. END;
  132. END InitDevice;
  133. (* Read a single character chr from the device dev. This call is blocking *)
  134. PROCEDURE Read*( dev: Device; VAR chr: CHAR );
  135. VAR
  136. len: LONGINT;
  137. BEGIN
  138. REPEAT len := 1; dev.Read( dev, chr, 0, len ); UNTIL len = 1;
  139. END Read;
  140. (* Write a single character "chr" to the device "dev". This call is blocking *)
  141. PROCEDURE Write*( dev: Device; chr: CHAR );
  142. VAR
  143. len: LONGINT;
  144. BEGIN
  145. REPEAT len := 1; dev.Write( dev, chr, 0, len ) UNTIL len = 1;
  146. END Write;
  147. (* Routines to write and read all standard Oberon types. A read an write pair for all types is provided.
  148. Note that all calls are blocking *)
  149. PROCEDURE ReadBool*( dev: Device; VAR bool: BOOLEAN );
  150. VAR
  151. ch: CHAR;
  152. BEGIN
  153. Read( dev, ch ); bool := ch # 0X
  154. END ReadBool;
  155. PROCEDURE WriteBool*( dev: Device; x: BOOLEAN );
  156. VAR
  157. c: CHAR;
  158. BEGIN
  159. IF x THEN
  160. c := 1X;
  161. ELSE
  162. c := 0X;
  163. END;
  164. Write( dev, c )
  165. END WriteBool;
  166. (* Read len bytes from the device dev and store them in buf starting at location offset. This call is blocking *)
  167. PROCEDURE ReadBytes( dev: Device; VAR buf: ARRAY OF SYSTEM.BYTE; offset, len: LONGINT );
  168. VAR
  169. receive: LONGINT;
  170. BEGIN
  171. len := offset + len;
  172. WHILE offset < len DO
  173. receive := len - offset; dev.Read( dev, buf, offset, receive );
  174. offset := offset + receive;
  175. END;
  176. END ReadBytes;
  177. (* Write len bytes from the device dev and store them in buf starting at location offset. This call is blocking *)
  178. PROCEDURE WriteBytes*( dev: Device; CONST buf: ARRAY OF SYSTEM.BYTE; offset, len: LONGINT );
  179. VAR
  180. toSend: LONGINT;
  181. BEGIN
  182. len := offset + len;
  183. WHILE offset < len DO
  184. toSend := len - offset; dev.Write( dev, buf, offset, toSend );
  185. offset := offset + toSend;
  186. END;
  187. END WriteBytes;
  188. PROCEDURE ReadChars*( dev: Device; VAR buf: ARRAY OF CHAR; offset, len: LONGINT );
  189. BEGIN
  190. ReadBytes( dev, buf, offset, len );
  191. END ReadChars;
  192. PROCEDURE WriteChars*( dev: Device; CONST buf: ARRAY OF CHAR; offset, len: LONGINT );
  193. BEGIN
  194. WriteBytes( dev, buf, offset, len );
  195. END WriteChars;
  196. PROCEDURE ReadInt*( dev: Device; VAR int: LONGINT );
  197. BEGIN
  198. ReadBytes( dev, int, 0, 4 );
  199. END ReadInt;
  200. PROCEDURE WriteInt*( dev: Device; int: LONGINT );
  201. BEGIN
  202. WriteBytes( dev, int, 0, 4 );
  203. END WriteInt;
  204. PROCEDURE ReadReal*( dev: Device; VAR real: REAL );
  205. BEGIN
  206. ReadBytes( dev, real, 0, 4 );
  207. END ReadReal;
  208. PROCEDURE WriteReal*( dev: Device; real: REAL );
  209. BEGIN
  210. WriteBytes( dev, real, 0, 4 );
  211. END WriteReal;
  212. PROCEDURE ReadSet*( dev: Device; VAR set: SET );
  213. BEGIN
  214. ReadBytes( dev, set, 0, 4 );
  215. END ReadSet;
  216. PROCEDURE WriteSet*( dev: Device; set: SET );
  217. BEGIN
  218. WriteBytes( dev, set, 0, 4 );
  219. END WriteSet;
  220. PROCEDURE ReadStr*( dev: Device; VAR buf: ARRAY OF CHAR );
  221. VAR i: LONGINT; ch: CHAR;
  222. BEGIN
  223. i := 0;
  224. REPEAT Read( dev, ch ); buf[i] := ch; INC( i ) UNTIL ((ch = 0X) OR (i >= LEN( buf )));
  225. buf[i - 1] := 0X;
  226. END ReadStr;
  227. PROCEDURE WriteStr*( dev: Device; CONST buf: ARRAY OF CHAR );
  228. VAR len: LONGINT;
  229. BEGIN
  230. len := 0;
  231. WHILE (len < LEN( buf ) - 1) & (buf[len] # 0X) DO INC( len );
  232. END;
  233. INC( len ); WriteChars( dev, buf, 0, len );
  234. END WriteStr;
  235. (* Just here to make the interface consistent *)
  236. PROCEDURE Available*( dev: Device ): LONGINT;
  237. BEGIN
  238. RETURN dev.Available( dev )
  239. END Available;
  240. (* Just here to make the interface consistent *)
  241. PROCEDURE Free*( dev: Device ): LONGINT;
  242. BEGIN
  243. RETURN dev.Free( dev )
  244. END Free;
  245. (* Just here to make the interface consistent *)
  246. PROCEDURE Flush*( dev: Device );
  247. BEGIN
  248. dev.Flush( dev )
  249. END Flush;
  250. (* Just here to make the interface consistent *)
  251. PROCEDURE Open*( dev: Device );
  252. BEGIN
  253. dev.Open( dev )
  254. END Open;
  255. (* Just here to make the interface consistent *)
  256. PROCEDURE Close*( dev: Device );
  257. BEGIN
  258. dev.Close( dev )
  259. END Close;
  260. (* Just here to make the interface consistent *)
  261. PROCEDURE Command*( dev: Device; cmd, param: LONGINT; VAR res: LONGINT );
  262. BEGIN
  263. dev.Command( dev, cmd, param, res );
  264. END Command;
  265. BEGIN
  266. devices := NIL;
  267. NEW( null );
  268. InitDevice( null ); Install( null, "NULL" );
  269. END Device.
  270. Device.DumpDevices