Unix.V24.Mod 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. MODULE V24; (** AUTHOR "F.Necati"; PURPOSE "V24 serial lines"; *)
  2. IMPORT Unix, Log := KernelLog, Serials, Objects, Commands, Strings;
  3. CONST
  4. (* modem lines bits *)
  5. TIOCM_LE = 0; TIOCM_DTR = 1; TIOCM_RTS = 2; TIOCM_ST = 3;
  6. TIOCM_SR = 4; TIOCM_CTS = 5; TIOCM_CAR = 6; TIOCM_RNG = 7;
  7. TIOCM_DSR = 8; TIOCM_CD = TIOCM_CAR; TIOCM_RI = TIOCM_RNG;
  8. (* tio.iflag bits *)
  9. IGNBRK = {0};
  10. BRKINT = {1};
  11. IGNPAR = {2};
  12. (* tcsetattr actions *)
  13. TCSANOW = 0;
  14. TCSADRAIN = 1;
  15. TCSAFLUSH = 2;
  16. NumberOfPorts = 4;
  17. VAR
  18. tcgetattr : PROCEDURE {C} ( fd: LONGINT; VAR tio: Unix.Termios ): LONGINT;
  19. tcsetattr : PROCEDURE {C} ( fd: LONGINT; action: LONGINT; VAR tio: Unix.Termios ): LONGINT;
  20. cfsetispeed : PROCEDURE {C} ( VAR tio: Unix.Termios; speed: LONGINT ): LONGINT;
  21. cfsetospeed : PROCEDURE {C} ( VAR tio: Unix.Termios; speed: LONGINT ): LONGINT;
  22. cfgetispeed : PROCEDURE {C} ( VAR tio: Unix.Termios ): LONGINT;
  23. cfgetospeed : PROCEDURE {C} ( VAR tio: Unix.Termios ): LONGINT;
  24. TYPE
  25. Port* = OBJECT (Serials.Port)
  26. VAR
  27. fd: LONGINT;
  28. portname: ARRAY 128 OF CHAR;
  29. PROCEDURE & Init*( port: LONGINT; CONST name: ARRAY OF CHAR );
  30. BEGIN
  31. COPY(name, portname);
  32. fd := 0;
  33. END Init;
  34. (* adapted from LNO.V24.Mod *)
  35. PROCEDURE Open*( bps, data, parity, stop: LONGINT; VAR res: WORD );
  36. VAR
  37. err, speed: LONGINT;
  38. tio: Unix.Termios;
  39. BEGIN {EXCLUSIVE}
  40. IF fd > 0 THEN res := Serials.PortInUse; RETURN END;
  41. IF (data < 5) OR ( data > 8) OR ( parity = Serials.ParMark) OR
  42. ( parity = Serials.ParSpace) OR (stop = Serials.Stop1dot5) THEN
  43. res := Serials.WrongData; RETURN;
  44. END;
  45. fd := Unix.open( ADDRESSOF(portname), Unix.rdwr, 0 );
  46. IF fd = -1 THEN
  47. fd := 0; res := Serials.NoSuchPort; RETURN
  48. END;
  49. err := tcgetattr( fd, tio );
  50. tio.iflags:= IGNBRK + IGNPAR;
  51. tio.oflags:={};
  52. tio.cflags:= Unix.CREAD + Unix.HUPCL + Unix.CLOCAL;
  53. tio.lflags:={};
  54. IF bps < 50 THEN speed := Unix.B0
  55. ELSIF bps < 75 THEN speed := Unix.B50
  56. ELSIF bps < 110 THEN speed := Unix.B75
  57. ELSIF bps < 134 THEN speed := Unix.B110
  58. ELSIF bps < 150 THEN speed := Unix.B134
  59. ELSIF bps < 200 THEN speed := Unix.B150
  60. ELSIF bps < 300 THEN speed := Unix.B200
  61. ELSIF bps < 600 THEN speed := Unix.B300
  62. ELSIF bps < 1200 THEN speed := Unix.B600
  63. ELSIF bps < 1800 THEN speed := Unix.B1200
  64. ELSIF bps < 2400 THEN speed := Unix.B1800
  65. ELSIF bps < 4800 THEN speed := Unix.B2400
  66. ELSIF bps < 9600 THEN speed := Unix.B4800
  67. ELSIF bps < 19200 THEN speed := Unix.B9600
  68. ELSIF bps < 38400 THEN speed := Unix.B19200
  69. ELSIF bps < 57600 THEN speed := Unix.B38400
  70. ELSIF bps < 115200 THEN speed := Unix.B57600
  71. ELSIF bps < 230400 THEN speed := Unix.B115200
  72. ELSE speed := Unix.B230400
  73. END;
  74. err := cfsetispeed( tio, speed );
  75. err := cfsetospeed( tio, speed );
  76. tio.cflags := tio.cflags - Unix.CSIZE;
  77. IF data= 5 THEN tio.cflags:= tio.cflags + Unix.CS5;
  78. ELSIF data= 6 THEN tio.cflags:= tio.cflags + Unix.CS6;
  79. ELSIF data= 7 THEN tio.cflags:= tio.cflags + Unix.CS7;
  80. ELSIF data= 8 THEN tio.cflags:= tio.cflags + Unix.CS8;
  81. END;
  82. IF parity # Serials.ParNo THEN
  83. tio.cflags := tio.cflags + Unix.PARENB;
  84. IF parity= Serials.ParOdd THEN tio.cflags := tio.cflags + Unix.PARODD END;
  85. END;
  86. IF stop= Serials.Stop2 THEN tio.cflags := tio.cflags + Unix.CSTOPB END;
  87. err := tcsetattr( fd, TCSAFLUSH, tio);
  88. IF err # -1 THEN
  89. Log.String( "V24 opened the port: " ); Log.String( portname ); Log.Ln;
  90. res := Serials.Ok;
  91. ELSE
  92. Close;
  93. res := Serials.NoSuchPort;
  94. END;
  95. END Open;
  96. PROCEDURE Close*;
  97. VAR err: LONGINT;
  98. BEGIN
  99. IF fd > 0 THEN
  100. err:= Unix.close( fd );
  101. fd := 0
  102. END
  103. END Close;
  104. PROCEDURE Available*(): LONGINT;
  105. VAR
  106. num, err: LONGINT;
  107. BEGIN
  108. err := Unix.ioctl( fd, Unix.FIONREAD, ADDRESSOF(num) );
  109. RETURN num;
  110. END Available;
  111. PROCEDURE ReceiveChar*( VAR ch: CHAR; VAR res: WORD );
  112. VAR r: SIZE;
  113. BEGIN
  114. r := Unix.read( fd, ADDRESSOF(ch), 1); res := LONGINT(r);
  115. IF res = 1 THEN
  116. INC( charactersReceived );
  117. res := Serials.Ok;
  118. ELSE
  119. res := Serials.TransportError;
  120. END;
  121. END ReceiveChar;
  122. (** Send - Send a byte to the specified port. Waits until buffer space is available. res = 0 iff ok. *)
  123. PROCEDURE SendChar*( ch: CHAR; VAR res: WORD );
  124. VAR r: SIZE;
  125. BEGIN
  126. r := Unix.write( fd, ADDRESSOF(ch), 1); res := LONGINT(r);
  127. IF res = 1 THEN
  128. INC( charactersSent );
  129. res := Serials.Ok;
  130. ELSE
  131. res := Serials.TransportError;
  132. END;
  133. END SendChar;
  134. PROCEDURE Send*( CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: WORD );
  135. VAR r: SIZE; writeRes: LONGINT;
  136. BEGIN
  137. ASSERT ( LEN( buf ) >= ofs + len ); (* array bound check not implemented in Kernel32.WriteFile *)
  138. r := Unix.write( fd, ADDRESSOF(buf[ofs]), len ); writeRes := LONGINT( r );
  139. IF writeRes < 0 THEN
  140. res := Serials.TransportError;
  141. ELSE
  142. INC( charactersSent, writeRes );
  143. res := Serials.Ok;
  144. END;
  145. END Send;
  146. PROCEDURE Receive*( VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len: LONGINT; VAR res: WORD );
  147. VAR i, l: LONGINT; read: SIZE;
  148. BEGIN
  149. ASSERT ( LEN( buf ) >= ofs + size );
  150. ASSERT ( LEN( buf ) >= ofs + min ); (* array bound check not implemented in Kernel32.ReadFile *)
  151. res := Serials.Ok; len := 0;
  152. i := ofs; l := Available();
  153. WHILE (res = Serials.Ok) & ( (min > 0) OR ((l > 0) & (size > 0)) ) DO (* fof 060804 *)
  154. IF l > size THEN l := size END;
  155. IF l > 0 THEN
  156. read := Unix.read(fd, ADDRESSOF(buf[i]), l );
  157. IF read = l THEN
  158. charactersReceived := charactersReceived + LONGINT(read);
  159. DEC( min, l ); DEC( size, l ); INC( len, l ); INC( i, l );
  160. ELSE
  161. (* If we've already received <min> bytes, <res> will become Serials.Ok later *)
  162. res := Serials.TransportError;
  163. END;
  164. END;
  165. l := Available();
  166. IF (res = Serials.Ok) & ( (min > 0) OR ((l > 0) & (size > 0)) ) THEN
  167. Objects.Sleep(1);
  168. END;
  169. END;
  170. IF min <= 0 THEN res := Serials.Ok END;
  171. END Receive;
  172. (** Get the port state: state (open, closed), speed in bps, no. of data bits, parity, stop bit length. *)
  173. PROCEDURE GetPortState*( VAR openstat : BOOLEAN; VAR bps, data, parity, stop : LONGINT );
  174. VAR
  175. err, br: LONGINT; t: SET; tio: Unix.Termios;
  176. BEGIN
  177. IF fd > 0 THEN
  178. err := tcgetattr( fd, tio );
  179. br := cfgetispeed( tio );
  180. IF br = Unix.B0 THEN bps := 0
  181. ELSIF br = Unix.B50 THEN bps := 50
  182. ELSIF br = Unix.B75 THEN bps := 75
  183. ELSIF br = Unix.B110 THEN bps := 110
  184. ELSIF br = Unix.B134 THEN bps := 134
  185. ELSIF br = Unix.B150 THEN bps := 150
  186. ELSIF br = Unix.B200 THEN bps := 200
  187. ELSIF br = Unix.B300 THEN bps := 300
  188. ELSIF br = Unix.B600 THEN bps := 600
  189. ELSIF br = Unix.B1200 THEN bps := 1200
  190. ELSIF br = Unix.B1800 THEN bps := 1800
  191. ELSIF br = Unix.B2400 THEN bps := 2400
  192. ELSIF br = Unix.B4800 THEN bps := 4800
  193. ELSIF br = Unix.B9600 THEN bps := 9600
  194. ELSIF br = Unix.B19200 THEN bps := 19200
  195. ELSIF br = Unix.B38400 THEN bps := 38400
  196. ELSIF br = Unix.B57600 THEN bps := 57600
  197. ELSIF br = Unix.B115200 THEN bps := 115200
  198. ELSIF br = Unix.B230400 THEN bps := 230400
  199. ELSE bps := -1
  200. END;
  201. t := tio.cflags*Unix.CSIZE;
  202. IF t = Unix.CS8 THEN data := 8
  203. ELSIF t = Unix.CS7 THEN data := 7
  204. ELSIF t = Unix.CS6 THEN data := 6
  205. ELSE data := 5
  206. END;
  207. IF tio.cflags*Unix.PARENB = {} THEN parity := Serials.ParNo
  208. ELSIF tio.cflags*Unix.PARODD = Unix.PARODD THEN parity := Serials.ParOdd
  209. ELSE parity := Serials.ParEven
  210. END;
  211. IF tio.cflags*Unix.CSTOPB = {} THEN stop := Serials.Stop1 ELSE stop := Serials.Stop2 END
  212. ELSE
  213. openstat := FALSE
  214. END
  215. END GetPortState;
  216. (** Clear the specified modem control lines. s may contain DTR, RTS & Break. *)
  217. PROCEDURE ClearMC*( s: SET );
  218. VAR
  219. err : LONGINT; stat: SET;
  220. BEGIN
  221. err := Unix.ioctl( fd, Unix.TIOCMGET , ADDRESSOF(stat) );
  222. IF Serials.DTR IN s THEN EXCL( stat, TIOCM_DTR ) END;
  223. IF Serials.RTS IN s THEN EXCL( stat, TIOCM_RTS ) END;
  224. err := Unix.ioctl( fd, Unix.TIOCMSET , ADDRESSOF(stat) );
  225. END ClearMC;
  226. (** Set the specified modem control lines. s may contain DTR, RTS & Break. *)
  227. PROCEDURE SetMC*( s: SET );
  228. VAR
  229. err : LONGINT; stat: SET;
  230. BEGIN
  231. err := Unix.ioctl( fd, Unix.TIOCMGET , ADDRESSOF(stat) );
  232. IF Serials.DTR IN s THEN INCL( stat, TIOCM_DTR ) ELSE EXCL( stat, TIOCM_DTR ) END;
  233. IF Serials.RTS IN s THEN INCL( stat, TIOCM_RTS ) ELSE EXCL( stat, TIOCM_RTS ) END;
  234. err := Unix.ioctl( fd, Unix.TIOCMSET , ADDRESSOF(stat) );
  235. END SetMC;
  236. (** Return the state of the specified modem control lines. s contains
  237. the current state of DSR, CTS, RI, DCD & Break Interrupt. *)
  238. PROCEDURE GetMC*( VAR s: SET );
  239. VAR
  240. err : LONGINT; stat: SET;
  241. BEGIN
  242. err := Unix.ioctl( fd, Unix.TIOCMGET , ADDRESSOF(stat) );
  243. IF TIOCM_DTR IN stat THEN INCL( s, Serials.DTR ) END;
  244. IF TIOCM_RTS IN stat THEN INCL( s, Serials.RTS ) END;
  245. (* IF TIOCM_LE IN stat THEN INCL(s, Serials.Break) END; *) (* ?? *)
  246. IF TIOCM_DSR IN stat THEN INCL( s, Serials.DSR ) END;
  247. IF TIOCM_CTS IN stat THEN INCL( s, Serials.CTS ) END;
  248. IF TIOCM_RI IN stat THEN INCL( s, Serials.RI ) END;
  249. IF TIOCM_CAR IN stat THEN INCL( s, Serials.DCD ) END;
  250. END GetMC;
  251. END Port;
  252. PROCEDURE Install*();
  253. VAR i: LONGINT;
  254. port: Port;
  255. name, ttyname: ARRAY 128 OF CHAR;
  256. BEGIN
  257. FOR i := 0 TO NumberOfPorts - 1 DO
  258. name:="COM ";
  259. name[3]:= CHR( i + ORD("1") );
  260. ttyname:="/dev/ttySx";
  261. ttyname[ 9]:= CHR( i + ORD("0") );
  262. NEW( port, i , ttyname);
  263. Serials.RegisterOnboardPort( i+1 , port, name, ttyname);
  264. END;
  265. END Install;
  266. PROCEDURE Map*(context: Commands.Context);
  267. VAR number: LONGINT; name, ttyname: ARRAY 128 OF CHAR; port: Port;
  268. BEGIN
  269. IF context.arg.GetInteger(number, FALSE) & context.arg.GetString(ttyname) THEN
  270. name := "COM";
  271. Strings.AppendInt(name, number);
  272. NEW(port, number, ttyname);
  273. Serials.RegisterOnboardPort( number, port, name, ttyname);
  274. END;
  275. END Map;
  276. PROCEDURE Initialize;
  277. BEGIN
  278. Unix.Dlsym( Unix.libc, "tcgetattr", ADDRESSOF( tcgetattr ) );
  279. Unix.Dlsym( Unix.libc, "tcsetattr", ADDRESSOF( tcsetattr ) );
  280. Unix.Dlsym( Unix.libc, "cfgetispeed", ADDRESSOF( cfgetispeed ) );
  281. Unix.Dlsym( Unix.libc, "cfgetospeed", ADDRESSOF( cfgetospeed ) );
  282. Unix.Dlsym( Unix.libc, "cfsetispeed", ADDRESSOF( cfsetispeed ) );
  283. Unix.Dlsym( Unix.libc, "cfsetospeed", ADDRESSOF( cfsetospeed ) );
  284. END Initialize
  285. BEGIN
  286. Initialize;
  287. (* Install;*)
  288. END V24.
  289. V24.Install ~
  290. V24.Map 5 ttyUSB0 ~
  291. Serials.Show ~
  292. System.Free V24~
  293. install /dev/ttySx as :
  294. COM1 -> /dev/ttyS0
  295. COM2 -> /dev/ttyS1
  296. COM3 -> /dev/ttyS2
  297. COM4 -> /dev/ttyS3
  298. On Solaris and Darwin hosts the tty lines have different names.
  299. To make them useable for Aos create symbolic links
  300. Solaris: ln -s /dev/ttya /dev/ttyS0
  301. ------------------------------------------
  302. you must have access rights to serial port:
  303. first method:
  304. must give username exclusive access to the device file, the first serial port on linux:
  305. # chown username /dev/ttyS0
  306. # chmod 0600 /dev/ttyS0
  307. # ls -ls /dev/ttyS0
  308. second method: allow anybody to use serial port 0 (be carefull for security)
  309. # chmod a+rw /dev/ttyS0
  310. ---------------------
  311. permanent setting:
  312. # groups
  313. see which groups you belong
  314. if you dont belong to "dialout" group, add yourself to this group by
  315. # sudo usermode -a -G dialout your_username
  316. or
  317. # sudo adduser your_username group
  318. logout and login to system. that is all.
  319. removing:
  320. # sudo deluser your_username group
  321. ---------------------
  322. ------------------------------------------