MODULE Bluetooth;
IMPORT
Objects, Streams;
CONST
Ok* = 0;
ErrTimeout* = -1;
ErrInvalidPacket* = -2;
ErrInvalidEvent* = -3;
ErrInvalidParameters* = -4;
ErrSendError* = -5;
BDAddrLen* = 6;
DeviceClassLen* = 3;
TYPE
BDAddr* = ARRAY BDAddrLen OF CHAR;
DeviceClass* = ARRAY DeviceClassLen OF CHAR;
CONST
Default* = 0;
Command* = 1;
ACL* = 2;
SCO* = 3;
Event* = 4;
Error* = 5;
Negotiation* = 6;
NumQueues = 7;
MaxACLDataLen* = 256;
MaxSCODataLen* = 256;
MaxEventParamLen* = 256;
MaxUnknownDataLen* = 256;
MaxLen* = 256;
TYPE
Packet* = POINTER TO RECORD
next: Packet
END;
ACLPacket* = POINTER TO RECORD(Packet)
handle*,
PB*,
BC*,
len*: LONGINT;
data*: ARRAY MaxACLDataLen OF CHAR
END;
SCOPacket* = POINTER TO RECORD(Packet)
handle*,
len*: LONGINT;
data*: ARRAY MaxSCODataLen OF CHAR
END;
EventPacket* = POINTER TO RECORD(Packet)
code*: CHAR;
paramLen*: LONGINT;
params*: ARRAY MaxEventParamLen OF CHAR
END;
UnknownPacket* = POINTER TO RECORD(Packet)
len*: LONGINT;
data*: ARRAY MaxUnknownDataLen OF CHAR
END;
PacketFilter* = PROCEDURE{DELEGATE} (packet: Packet): BOOLEAN;
PacketNotify* = PROCEDURE{DELEGATE} (packet: Packet);
Filter = POINTER TO RECORD
filter: PacketFilter;
notify: PacketNotify;
next: Filter
END;
IDTimer* = OBJECT
VAR
t: Objects.Timer;
handler: IDTimerHandler;
PROCEDURE &Init*(handler: IDTimerHandler; timeout: LONGINT);
BEGIN
SELF.handler := handler; NEW(t);
Objects.SetTimeout(t, TimeoutHandler, timeout)
END Init;
PROCEDURE Cancel*;
BEGIN {EXCLUSIVE} Objects.CancelTimeout(t)
END Cancel;
PROCEDURE TimeoutHandler;
BEGIN {EXCLUSIVE} handler(SELF)
END TimeoutHandler;
END IDTimer;
IDTimerHandler* = PROCEDURE {DELEGATE} (sender: IDTimer);
Queue* = OBJECT
VAR
head, tail: Packet;
filters: Filter;
dead: BOOLEAN;
expired: IDTimer;
getNext: Packet;
inGetNext: LONGINT;
PROCEDURE &Init*;
BEGIN
inGetNext := 0; dead := FALSE;
NEW(filters)
END Init;
PROCEDURE Close*;
BEGIN {EXCLUSIVE}
dead := TRUE
END Close;
PROCEDURE Clear*;
BEGIN {EXCLUSIVE}
head := NIL; tail := NIL
END Clear;
PROCEDURE Add*(packet: Packet);
BEGIN
IF ~CheckPacketFilters(packet) THEN
BEGIN {EXCLUSIVE}
IF (tail # NIL) THEN tail.next := packet; tail := packet
ELSE head := packet; tail := packet
END
END
END
END Add;
PROCEDURE HandleTimeout(sender: IDTimer);
BEGIN {EXCLUSIVE} expired := sender
END HandleTimeout;
PROCEDURE Get*(VAR p: Packet; timeout: LONGINT; VAR res: LONGINT);
VAR timer: IDTimer;
BEGIN {EXCLUSIVE}
IF (head = NIL) THEN
NEW(timer, HandleTimeout, timeout);
AWAIT((head # NIL) OR (expired = timer) OR dead);
IF (expired # timer) THEN timer.Cancel END
END;
IF (head # NIL) THEN
p := head; head := head.next;
IF (head = NIL) THEN tail := NIL END;
p.next := NIL; res := 0
ELSE
p := NIL; res := ErrTimeout
END
END Get;
PROCEDURE GetNextFilter(p: Packet): BOOLEAN;
BEGIN
RETURN TRUE
END GetNextFilter;
PROCEDURE GetNextHandler(p: Packet);
BEGIN
getNext := p
END GetNextHandler;
PROCEDURE GetNext*(VAR p: Packet; timeout: LONGINT; VAR res: LONGINT);
VAR f: Filter; timer: IDTimer;
BEGIN {EXCLUSIVE}
AWAIT(inGetNext = 0); INC(inGetNext);
getNext := NIL;
NEW(f); f.filter := GetNextFilter; f.notify := GetNextHandler;
f.next := filters.next; filters.next := f;
NEW(timer, HandleTimeout, timeout);
AWAIT((getNext # NIL) OR (expired = timer) OR dead);
filters.next := f.next;
IF (getNext # NIL) THEN p := getNext; res := 0
ELSE p := NIL; res := ErrTimeout
END;
DEC(inGetNext)
END GetNext;
PROCEDURE RegisterPacketFilter*(filter: PacketFilter; notify: PacketNotify);
VAR f: Filter;
BEGIN {EXCLUSIVE}
NEW(f); f.filter := filter; f.notify := notify;
f.next := filters.next; filters.next := f
END RegisterPacketFilter;
PROCEDURE UnregisterPacketFilter*(notify: PacketNotify);
VAR p,q: Filter;
BEGIN {EXCLUSIVE}
q := filters.next; p := filters;
WHILE (q # NIL) DO
IF (q.notify = notify) THEN
p.next := q.next
END;
q := q.next
END
END UnregisterPacketFilter;
PROCEDURE CheckPacketFilters(packet: Packet): BOOLEAN;
VAR f: Filter; notify: PacketNotify; res: BOOLEAN;
BEGIN
res := FALSE;
BEGIN {EXCLUSIVE}
notify := NIL;
f := filters.next;
WHILE (f # NIL) DO
IF f.filter(packet) THEN res := TRUE; notify := f.notify; f := NIL
ELSE f := f.next
END
END
END;
IF (notify # NIL) THEN notify(packet) END;
RETURN res
END CheckPacketFilters;
END Queue;
TransportLayer* = OBJECT
VAR
name-: ARRAY 32 OF CHAR;
out*: Streams.Writer;
in*: Streams.Reader;
sink-: ARRAY NumQueues OF Queue;
PROCEDURE &Init*(name: ARRAY OF CHAR; sender: Streams.Sender; receiver: Streams.Receiver);
VAR q: Queue;
BEGIN
COPY(name, SELF.name);
NEW(q); sink[Default] := q
END Init;
PROCEDURE Close*;
END Close;
PROCEDURE SetSink*(type: LONGINT; queue: Queue);
BEGIN {EXCLUSIVE}
sink[type] := queue
END SetSink;
PROCEDURE GetSink*(type: LONGINT): Queue;
BEGIN {EXCLUSIVE}
RETURN sink[type]
END GetSink;
PROCEDURE Send*(type: LONGINT; VAR data: ARRAY OF CHAR; ofs, len: LONGINT; VAR res: LONGINT);
BEGIN
HALT(301)
END Send;
PROCEDURE Send1H*(type: LONGINT; VAR hdr: ARRAY OF CHAR; hdrlen: LONGINT; VAR data: ARRAY OF CHAR; ofs, len: LONGINT; VAR res: LONGINT);
BEGIN
HALT(301)
END Send1H;
PROCEDURE Send2H*(type: LONGINT; VAR hdr1: ARRAY OF CHAR; hdr1len: LONGINT;
VAR hdr2: ARRAY OF CHAR; hdr2len: LONGINT;
VAR data: ARRAY OF CHAR; ofs, len: LONGINT; VAR res: LONGINT);
BEGIN
HALT(301)
END Send2H;
END TransportLayer;
PROCEDURE StringToParam*(string: ARRAY OF CHAR; VAR param: ARRAY OF CHAR; VAR len: LONGINT);
VAR i, h, l: LONGINT; error: BOOLEAN;
PROCEDURE Value(c: CHAR): LONGINT;
BEGIN
IF ("0" <= c) & (c <= "9") THEN RETURN ORD(c)-ORD("0")
ELSE
c := CAP(c);
IF ("A" <= c) & (c <= "F") THEN RETURN ORD(c)-ORD("A")+10 END
END;
RETURN -1
END Value;
BEGIN
i := 0; len := 0; error := FALSE;
WHILE ~error & (string[i] # 0X) DO
h := Value(string[i]); l := Value(string[i+1]);
IF (h # -1) & (l # -1) THEN
param[len] := CHR(h*10H+l); INC(len);
INC(i, 2);
IF (string[i] # 0X) THEN
IF (string[i] = " ") THEN INC(i)
ELSE error := TRUE; len := 0
END
END
ELSE error := TRUE; len := 0
END
END;
param[len] := 0X
END StringToParam;
PROCEDURE CharArrayToString*(buf: ARRAY OF CHAR; ofs, len: LONGINT; VAR string: ARRAY OF CHAR);
VAR i, pos, maxLen: LONGINT; c: CHAR;
PROCEDURE Char(v: LONGINT): CHAR;
BEGIN
ASSERT((0 <= v) & (v < 10H));
IF (v < 10) THEN RETURN CHR(ORD("0") + v)
ELSE RETURN CHR(ORD("A") + v - 10)
END
END Char;
BEGIN
i := 0; pos := 0; maxLen := LEN(string)-1-3;
WHILE (i < len) & (pos < maxLen) DO
c := buf[ofs+i];
string[pos] := Char(ORD(c) DIV 10H); INC(pos);
string[pos] := Char(ORD(c) MOD 10H); INC(pos);
string[pos] := " "; INC(pos);
INC(i)
END;
string[pos] := 0X
END CharArrayToString;
END Bluetooth.