Bluetooth.Mod 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. MODULE Bluetooth; (** AUTHOR "be"; PURPOSE "Core Bluetooth types/functions"; *)
  2. IMPORT
  3. Objects, Streams;
  4. (**---- general Bluetooth types ----*)
  5. CONST
  6. (** Result codes. res > 0: command specific error *)
  7. Ok* = 0;
  8. ErrTimeout* = -1;
  9. ErrInvalidPacket* = -2;
  10. ErrInvalidEvent* = -3;
  11. ErrInvalidParameters* = -4;
  12. ErrSendError* = -5;
  13. BDAddrLen* = 6; (** length of Bluetooth device address *)
  14. DeviceClassLen* = 3; (** length of Bluetooth class of device *)
  15. TYPE
  16. BDAddr* = ARRAY BDAddrLen OF CHAR; (** Bluetooth device address *)
  17. DeviceClass* = ARRAY DeviceClassLen OF CHAR; (** Bluetooth class of device *)
  18. (**---- HCI packet queue ----*)
  19. CONST
  20. (** queue types *)
  21. Default* = 0; (** default queue *)
  22. Command* = 1; (** command queue *)
  23. ACL* = 2; (** ACL data packet queue *)
  24. SCO* = 3; (** SCO data packet queue *)
  25. Event* = 4; (** HCI event queue *)
  26. Error* = 5; (** error queue *)
  27. Negotiation* = 6; (** negotiation queue *)
  28. NumQueues = 7;
  29. MaxACLDataLen* = 256;
  30. MaxSCODataLen* = 256;
  31. MaxEventParamLen* = 256;
  32. MaxUnknownDataLen* = 256;
  33. MaxLen* = 256;
  34. TYPE
  35. Packet* = POINTER TO RECORD (** generic packet type *)
  36. next: Packet
  37. END;
  38. ACLPacket* = POINTER TO RECORD(Packet) (** ACL packet, see specs chapter 4.4.3 *)
  39. handle*, (** connection handle *)
  40. PB*, (** packet boundary flag *)
  41. BC*, (** broadcast flag *)
  42. len*: LONGINT; (** length of data, in bytes *)
  43. data*: ARRAY MaxACLDataLen OF CHAR (** data *)
  44. END;
  45. SCOPacket* = POINTER TO RECORD(Packet) (** SCO packet, see specs chapter 4.4.3 *)
  46. handle*, (** connection handle *)
  47. len*: LONGINT; (** length of data, in bytes *)
  48. data*: ARRAY MaxSCODataLen OF CHAR (** data *)
  49. END;
  50. EventPacket* = POINTER TO RECORD(Packet) (** HCI event packet, see specs chapter 4.4.2 *)
  51. code*: CHAR; (** event code *)
  52. paramLen*: LONGINT; (** parameter length, in bytes *)
  53. params*: ARRAY MaxEventParamLen OF CHAR (** parameter values *)
  54. END;
  55. UnknownPacket* = POINTER TO RECORD(Packet) (** unknown packet...should not happen ;-) *)
  56. len*: LONGINT; (** length of data, in bytes *)
  57. data*: ARRAY MaxUnknownDataLen OF CHAR (** data *)
  58. END;
  59. (** packet filter/notifier: the filter is called first and should return quickly. If it returns TRUE the
  60. correspoding notifier will be called *)
  61. PacketFilter* = PROCEDURE{DELEGATE} (packet: Packet): BOOLEAN;
  62. PacketNotify* = PROCEDURE{DELEGATE} (packet: Packet);
  63. Filter = POINTER TO RECORD
  64. filter: PacketFilter;
  65. notify: PacketNotify;
  66. next: Filter
  67. END;
  68. (** used if we need to know which timer has expired *)
  69. IDTimer* = OBJECT
  70. VAR
  71. t: Objects.Timer;
  72. handler: IDTimerHandler;
  73. PROCEDURE &Init*(handler: IDTimerHandler; timeout: LONGINT);
  74. BEGIN
  75. SELF.handler := handler; NEW(t);
  76. Objects.SetTimeout(t, TimeoutHandler, timeout)
  77. END Init;
  78. PROCEDURE Cancel*;
  79. BEGIN {EXCLUSIVE} Objects.CancelTimeout(t)
  80. END Cancel;
  81. PROCEDURE TimeoutHandler;
  82. BEGIN {EXCLUSIVE} handler(SELF)
  83. END TimeoutHandler;
  84. END IDTimer;
  85. IDTimerHandler* = PROCEDURE {DELEGATE} (sender: IDTimer);
  86. (** packet queue *)
  87. Queue* = OBJECT
  88. VAR
  89. head, tail: Packet;
  90. filters: Filter;
  91. dead: BOOLEAN;
  92. expired: IDTimer;
  93. getNext: Packet;
  94. inGetNext: LONGINT;
  95. PROCEDURE &Init*;
  96. BEGIN
  97. inGetNext := 0; dead := FALSE;
  98. NEW(filters) (* dummy head *)
  99. END Init;
  100. (** closes a queue and aborts any pending 'Get' requests *)
  101. PROCEDURE Close*;
  102. BEGIN {EXCLUSIVE}
  103. dead := TRUE
  104. END Close;
  105. (** clears the queue *)
  106. PROCEDURE Clear*;
  107. BEGIN {EXCLUSIVE}
  108. head := NIL; tail := NIL
  109. END Clear;
  110. (** add a packet to the queue *)
  111. PROCEDURE Add*(packet: Packet);
  112. BEGIN
  113. IF ~CheckPacketFilters(packet) THEN (* packet filters are priorized *)
  114. BEGIN {EXCLUSIVE}
  115. IF (tail # NIL) THEN tail.next := packet; tail := packet
  116. ELSE head := packet; tail := packet
  117. END
  118. END
  119. END
  120. END Add;
  121. PROCEDURE HandleTimeout(sender: IDTimer);
  122. BEGIN {EXCLUSIVE} expired := sender
  123. END HandleTimeout;
  124. (** blocks until a HCI packet is available or a timeout occurs. Packet filters are priorized over the Get request *)
  125. PROCEDURE Get*(VAR p: Packet; timeout: LONGINT; VAR res: WORD);
  126. VAR timer: IDTimer;
  127. BEGIN {EXCLUSIVE}
  128. IF (head = NIL) THEN
  129. NEW(timer, HandleTimeout, timeout);
  130. AWAIT((head # NIL) OR (expired = timer) OR dead);
  131. IF (expired # timer) THEN timer.Cancel END
  132. END;
  133. IF (head # NIL) THEN
  134. p := head; head := head.next;
  135. IF (head = NIL) THEN tail := NIL END;
  136. p.next := NIL; res := 0
  137. ELSE
  138. p := NIL; res := ErrTimeout
  139. END
  140. END Get;
  141. (** blocks until the next HCI packet is available or a timeout occurs. Packet filters are priorized over the
  142. GetNext request.
  143. *)
  144. PROCEDURE GetNextFilter(p: Packet): BOOLEAN;
  145. BEGIN
  146. RETURN TRUE
  147. END GetNextFilter;
  148. PROCEDURE GetNextHandler(p: Packet);
  149. BEGIN
  150. getNext := p
  151. END GetNextHandler;
  152. (* naaa...won't work. besser: filter rein, der alles frisst, dann wieder rausnehmen *)
  153. PROCEDURE GetNext*(VAR p: Packet; timeout: LONGINT; VAR res: WORD);
  154. VAR f: Filter; timer: IDTimer;
  155. BEGIN {EXCLUSIVE}
  156. (* lock *)
  157. AWAIT(inGetNext = 0); INC(inGetNext);
  158. getNext := NIL;
  159. (* plug-in greedy filter *)
  160. NEW(f); f.filter := GetNextFilter; f.notify := GetNextHandler;
  161. f.next := filters.next; filters.next := f;
  162. NEW(timer, HandleTimeout, timeout);
  163. AWAIT((getNext # NIL) OR (expired = timer) OR dead);
  164. (* remove greedy filter *)
  165. filters.next := f.next;
  166. IF (getNext # NIL) THEN p := getNext; res := 0
  167. ELSE p := NIL; res := ErrTimeout
  168. END;
  169. (* unlock *)
  170. DEC(inGetNext)
  171. END GetNext;
  172. (** registers a packet filter/handler. Multiple filters/handlers may be registered *)
  173. PROCEDURE RegisterPacketFilter*(filter: PacketFilter; notify: PacketNotify);
  174. VAR f: Filter;
  175. BEGIN {EXCLUSIVE}
  176. NEW(f); f.filter := filter; f.notify := notify;
  177. f.next := filters.next; filters.next := f
  178. END RegisterPacketFilter;
  179. (** removes a registered filter/handler. *)
  180. PROCEDURE UnregisterPacketFilter*(notify: PacketNotify);
  181. VAR p,q: Filter;
  182. BEGIN {EXCLUSIVE}
  183. q := filters.next; p := filters;
  184. WHILE (q # NIL) DO
  185. IF (q.notify = notify) THEN
  186. p.next := q.next
  187. END;
  188. q := q.next
  189. END
  190. END UnregisterPacketFilter;
  191. (* checks if a packet filter/handler wants to handle the packet *)
  192. PROCEDURE CheckPacketFilters(packet: Packet): BOOLEAN;
  193. VAR f: Filter; notify: PacketNotify; res: BOOLEAN;
  194. BEGIN
  195. res := FALSE;
  196. BEGIN {EXCLUSIVE}
  197. notify := NIL;
  198. f := filters.next;
  199. WHILE (f # NIL) DO
  200. IF f.filter(packet) THEN res := TRUE; notify := f.notify; f := NIL
  201. ELSE f := f.next
  202. END
  203. END
  204. END;
  205. IF (notify # NIL) THEN notify(packet) END;
  206. RETURN res
  207. END CheckPacketFilters;
  208. END Queue;
  209. (**---- abstract transport layer ----*)
  210. TransportLayer* = OBJECT
  211. VAR
  212. name-: ARRAY 32 OF CHAR;
  213. out*: Streams.Writer;
  214. in*: Streams.Reader;
  215. sink-: ARRAY NumQueues OF Queue;
  216. PROCEDURE &Init*(name: ARRAY OF CHAR; sender: Streams.Sender; receiver: Streams.Receiver);
  217. VAR q: Queue;
  218. BEGIN
  219. COPY(name, SELF.name);
  220. NEW(q); sink[Default] := q (* install default queue *)
  221. END Init;
  222. (** close the transport layer *)
  223. PROCEDURE Close*;
  224. END Close;
  225. (** install a queue for certain HCI packet types *)
  226. PROCEDURE SetSink*(type: LONGINT; queue: Queue);
  227. BEGIN {EXCLUSIVE}
  228. sink[type] := queue
  229. END SetSink;
  230. (** get the queue for certain HCI packet types *)
  231. PROCEDURE GetSink*(type: LONGINT): Queue;
  232. BEGIN {EXCLUSIVE}
  233. RETURN sink[type]
  234. END GetSink;
  235. (** send a HCI packet *)
  236. PROCEDURE Send*(type: LONGINT; VAR data: ARRAY OF CHAR; ofs, len: LONGINT; VAR res: WORD);
  237. BEGIN
  238. HALT(301)
  239. END Send;
  240. PROCEDURE Send1H*(type: LONGINT; VAR hdr: ARRAY OF CHAR; hdrlen: LONGINT; VAR data: ARRAY OF CHAR; ofs, len: LONGINT; VAR res: WORD);
  241. BEGIN
  242. HALT(301)
  243. END Send1H;
  244. PROCEDURE Send2H*(type: LONGINT; VAR hdr1: ARRAY OF CHAR; hdr1len: LONGINT;
  245. VAR hdr2: ARRAY OF CHAR; hdr2len: LONGINT;
  246. VAR data: ARRAY OF CHAR; ofs, len: LONGINT; VAR res: WORD);
  247. BEGIN
  248. HALT(301)
  249. END Send2H;
  250. END TransportLayer;
  251. (** transforms 'character string' into an array of char.
  252. string = char { " " char } 0X.
  253. char = hexdigit hexdigit.
  254. hexdigit = "0"|..|"9"|"A"|..|"F".
  255. *)
  256. PROCEDURE StringToParam*(string: ARRAY OF CHAR; VAR param: ARRAY OF CHAR; VAR len: LONGINT);
  257. VAR i, h, l: LONGINT; error: BOOLEAN;
  258. PROCEDURE Value(c: CHAR): LONGINT;
  259. BEGIN
  260. IF ("0" <= c) & (c <= "9") THEN RETURN ORD(c)-ORD("0")
  261. ELSE
  262. c := CAP(c);
  263. IF ("A" <= c) & (c <= "F") THEN RETURN ORD(c)-ORD("A")+10 END
  264. END;
  265. RETURN -1
  266. END Value;
  267. BEGIN
  268. i := 0; len := 0; error := FALSE;
  269. WHILE ~error & (string[i] # 0X) DO
  270. h := Value(string[i]); l := Value(string[i+1]);
  271. IF (h # -1) & (l # -1) THEN
  272. param[len] := CHR(h*10H+l); INC(len);
  273. INC(i, 2);
  274. IF (string[i] # 0X) THEN
  275. IF (string[i] = " ") THEN INC(i)
  276. ELSE error := TRUE; len := 0
  277. END
  278. END
  279. ELSE error := TRUE; len := 0
  280. END
  281. END;
  282. param[len] := 0X
  283. END StringToParam;
  284. PROCEDURE CharArrayToString*(buf: ARRAY OF CHAR; ofs, len: LONGINT; VAR string: ARRAY OF CHAR);
  285. VAR i, pos, maxLen: LONGINT; c: CHAR;
  286. PROCEDURE Char(v: LONGINT): CHAR;
  287. BEGIN
  288. ASSERT((0 <= v) & (v < 10H));
  289. IF (v < 10) THEN RETURN CHR(ORD("0") + v)
  290. ELSE RETURN CHR(ORD("A") + v - 10)
  291. END
  292. END Char;
  293. BEGIN
  294. i := 0; pos := 0; maxLen := LEN(string)-1-3;
  295. WHILE (i < len) & (pos < maxLen) DO
  296. c := buf[ofs+i];
  297. string[pos] := Char(ORD(c) DIV 10H); INC(pos);
  298. string[pos] := Char(ORD(c) MOD 10H); INC(pos);
  299. string[pos] := " "; INC(pos);
  300. INC(i)
  301. END;
  302. string[pos] := 0X
  303. END CharArrayToString;
  304. END Bluetooth.