MODULE BluetoothRFCOMM;
IMPORT
S := SYSTEM,
BluetoothL2CAP,
Bluetooth,
Streams,
KernelLog;
CONST
ModuleName = "[BTRFCOMM]";
TraceBuffer = FALSE;
TraceChannel = FALSE;
TraceControlChannel = TRUE;
TraceRFCOMM = FALSE;
SABMFRAME = 02FH;
UAFRAME = 063H;
DMFRAME = 00FH;
DISCFRAME = 043H;
UIHFRAME = 0EFH;
DISCONNECTED = 0;
CONNECTING = 1;
NEGOTIATING = 2;
CONNECTED = 3;
DISCONNECTING = 4;
MAXBUFSIZE = 1024;
TYPE
Buffer = OBJECT
VAR
maxBufSize : LONGINT;
fifoBuffer : POINTER TO ARRAY OF CHAR;
head, tail : LONGINT;
dead : BOOLEAN;
PROCEDURE &Init*(maxBufSize : LONGINT);
BEGIN
SELF.maxBufSize := maxBufSize;
NEW(fifoBuffer,maxBufSize);
head := 0; tail := 0;
dead := FALSE;
END Init;
PROCEDURE Close;
BEGIN {EXCLUSIVE}
dead := TRUE;
END Close;
PROCEDURE Get(VAR ch : CHAR; VAR result : LONGINT);
BEGIN {EXCLUSIVE}
IF TraceBuffer THEN
KernelLog.String(ModuleName);
KernelLog.String("Buffer.Get: Await ... head = "); KernelLog.Int(head,0);
KernelLog.String(" tail = "); KernelLog.Int(tail,0);
KernelLog.Ln;
END;
AWAIT((tail # head) OR dead);
IF(tail#head) THEN
ch := fifoBuffer[head];
head := (head +1) MOD maxBufSize ;
result := 0;
ELSE
KernelLog.String(ModuleName);
KernelLog.String("Buffer.Get: error.");
KernelLog.Ln;
result := -1;
END;
IF TraceBuffer THEN
KernelLog.String(ModuleName);
KernelLog.String("Buffer.Get: done. result = "); KernelLog.Hex(result,-2);
KernelLog.Ln;
END;
END Get;
PROCEDURE Put(ch : CHAR; VAR result : LONGINT);
BEGIN {EXCLUSIVE}
IF((tail+1) MOD MAXBUFSIZE # head) THEN
fifoBuffer[tail] := ch;
tail := (tail +1) MOD maxBufSize ;
result := 0;
ELSE
KernelLog.String(ModuleName);
KernelLog.String("Buffer.Get: overflow.");
result := -1;
END;
END Put;
PROCEDURE IsFull() : BOOLEAN;
BEGIN {EXCLUSIVE}
IF((tail+1) MOD maxBufSize # head) THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END;
END IsFull;
PROCEDURE IsEmpty() : BOOLEAN;
BEGIN {EXCLUSIVE}
IF(tail # head) THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END;
END IsEmpty;
PROCEDURE Dump;
VAR
h,t,elements : LONGINT;
BEGIN {EXCLUSIVE}
h := head MOD maxBufSize;
t := tail MOD maxBufSize;
IF h<=t THEN
elements := t-h;
ELSE
elements := t-h+maxBufSize;
END;
KernelLog.String(ModuleName);
KernelLog.String("Buffer.Dump:"); KernelLog.Ln;
KernelLog.String("buffer size = "); KernelLog.Int(maxBufSize,0);
KernelLog.String(" head pos = "); KernelLog.Int(h,0);
KernelLog.String(" tail pos = "); KernelLog.Int(t,0);
KernelLog.String(" #elements = "); KernelLog.Int(elements,0);
KernelLog.Ln;
WHILE(h < t) DO
KernelLog.Hex(ORD(fifoBuffer[h]),-2); KernelLog.String(" ");
h := (h+1) MOD maxBufSize;
END;
KernelLog.Ln;
END Dump;
END Buffer;
Channel = OBJECT
VAR
dlci : LONGINT;
state : LONGINT;
rfcomm : RFCOMM;
receiveBuffer : Buffer;
PROCEDURE &Init*(rfcomm : RFCOMM; dlci : LONGINT);
BEGIN
SELF.rfcomm := rfcomm;
SELF.dlci := dlci;
SetState(DISCONNECTED);
NEW(receiveBuffer,MAXBUFSIZE);
END Init;
PROCEDURE Close;
BEGIN
SetState(DISCONNECTED);
receiveBuffer.Close();
END Close;
PROCEDURE SetState(state : LONGINT);
BEGIN {EXCLUSIVE}
SELF.state := state;
END SetState;
PROCEDURE W4State(state : LONGINT) : LONGINT;
BEGIN {EXCLUSIVE}
AWAIT((SELF.state = state) OR (SELF.state = DISCONNECTED));
RETURN SELF.state;
END W4State;
PROCEDURE SendSABM;
VAR
frame : ARRAY 4 OF CHAR;
BEGIN
IF (state = DISCONNECTED) THEN
frame[0] := CHR(dlci*4+3);
frame[1] := CHR(BITLOR(SABMFRAME,010H));
frame[2] := CHR(01H);
frame[3] := CalculateFCS(frame,3);
rfcomm.SendFrame(frame,4);
SetState(CONNECTING);
END;
END SendSABM;
PROCEDURE SendDISC;
VAR
frame : ARRAY 4 OF CHAR;
BEGIN
IF(state # DISCONNECTED) THEN
frame[0] := CHR(dlci*4+3);
frame[1] := CHR(BITLOR(DISCFRAME,010H));
frame[2] := CHR(01H);
frame[3] := CalculateFCS(frame,3);
rfcomm.SendFrame(frame,4);
SetState(DISCONNECTING);
END;
END SendDISC;
PROCEDURE SendUA;
VAR
frame : ARRAY 4 OF CHAR;
BEGIN
frame[0] := CHR(dlci*4+3);
frame[1] := CHR(BITLOR(UAFRAME,010H));
frame[2] := CHR(01H);
frame[3] := CalculateFCS(frame,3);
rfcomm.SendFrame(frame,4);
END SendUA;
PROCEDURE SendDM;
VAR
frame : ARRAY 4 OF CHAR;
BEGIN
frame[0] := CHR(dlci*4+3);
frame[1] := CHR(BITLOR(DMFRAME,010H));
frame[2] := CHR(01H);
frame[3] := CalculateFCS(frame,3);
rfcomm.SendFrame(frame,4);
END SendDM;
PROCEDURE SendUIH(info : ARRAY OF CHAR; infoLength : LONGINT);
VAR
frame : ARRAY 131 OF CHAR;
i : LONGINT;
BEGIN
ASSERT(infoLength < 128);
frame[0] := CHR(dlci * 4 + 3);
frame[1] := CHR(UIHFRAME);
frame[2] := CHR(infoLength * 2 +1);
FOR i := 0 TO infoLength-1 DO
frame[3+i] := info[i];
END;
frame[infoLength+3] := CalculateFCS(frame,2);
rfcomm.SendFrame(frame,infoLength + 4);
END SendUIH;
PROCEDURE ReceiveSABM;
BEGIN
IF TraceChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("Channel.ReceiveSABM: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.Ln;
END;
SendDM();
END ReceiveSABM;
PROCEDURE ReceiveUA;
BEGIN
IF TraceChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("Channel.ReceiveUA: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.Ln;
END;
IF(state = CONNECTING) THEN
SetState(CONNECTED);
ELSIF(state = DISCONNECTING) THEN
Close();
END;
END ReceiveUA;
PROCEDURE ReceiveDM;
BEGIN
IF TraceChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("Channel.ReceiveDM: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.Ln;
END;
Close();
END ReceiveDM;
PROCEDURE ReceiveDISC;
BEGIN
IF TraceChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("Channel.ReceiveDISC: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.Ln;
END;
IF(state = DISCONNECTED) THEN
SendDM();
ELSE
SendUA();
END;
Close();
END ReceiveDISC;
PROCEDURE ReceiveUIH(frame : ARRAY OF CHAR; frameLength : LONGINT);
VAR
infoLength : LONGINT;
result : LONGINT;
i : LONGINT;
BEGIN
IF TraceChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("Channel.ReceiveUIH: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.String(" infoLength = "); KernelLog.Int((ORD(frame[2]) - 1) DIV 2,0);
KernelLog.Ln;
END;
IF (state = CONNECTED) THEN
infoLength := (ORD(frame[2]) - 1) DIV 2;
ASSERT(infoLength < 128);
FOR i:= 0 TO infoLength-1 DO
IF (~receiveBuffer.IsFull()) THEN
receiveBuffer.Put(frame[3+i],result);
ASSERT(result = 0);
ELSE
KernelLog.String(ModuleName);
KernelLog.String("Channel.ReceiveUIH: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.String(" buffer overflow!");
KernelLog.Ln;
END;
END;
END;
END ReceiveUIH;
PROCEDURE CalculateFCS(data : ARRAY OF CHAR; length : LONGINT) : CHAR;
VAR
fcs : CHAR;
i : LONGINT;
BEGIN
fcs := CHR(0FFH);
i := 0;
WHILE (length > 0) DO
fcs := crcTable[ORD(BITCXOR(fcs,data[i]))];
INC(i); DEC(length)
END;
RETURN CHR(0FFH - ORD(fcs));
END CalculateFCS;
PROCEDURE Sender(CONST buf: ARRAY OF CHAR; ofs, len: LONGINT; propagate: BOOLEAN; VAR res: LONGINT);
VAR
info : ARRAY 127 OF CHAR;
infoLength : LONGINT;
i : LONGINT;
BEGIN
IF TraceChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("Channel.Sender: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.Ln;
END;
i := 0;
WHILE(i < len) DO
infoLength := 0;
WHILE((infoLength < LEN(info)) & (i < len)) DO
info[infoLength] := buf[i+ofs];
INC(infoLength); INC(i);
END;
SendUIH(info,infoLength);
END;
END Sender;
PROCEDURE Receiver(VAR buf: ARRAY OF CHAR; ofs, size, min: LONGINT; VAR len, res: LONGINT);
BEGIN
IF TraceChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("Channel.Receiver: dlci = "); KernelLog.Hex(dlci,-2);
KernelLog.Ln;
END;
len := 0;
res := 0;
WHILE((len < min) & (res = 0)) DO
receiveBuffer.Get(buf[ofs+len],res);
INC(len);
END;
WHILE((len < size) & (~receiveBuffer.IsEmpty()) & (res = 0)) DO
receiveBuffer.Get(buf[ofs+len],res);
INC(len);
END;
END Receiver;
END Channel;
ControlChannel = OBJECT (Channel)
PROCEDURE ReceiveUIH(info : ARRAY OF CHAR; length : LONGINT);
BEGIN
IF TraceControlChannel THEN
KernelLog.String(ModuleName);
KernelLog.String("ControlChannel.ReceiveUIH: multiplexer control command received.");
KernelLog.Ln;
END;
END ReceiveUIH;
END ControlChannel;
RFCOMM* = OBJECT
VAR
l2capLayer : BluetoothL2CAP.L2CAP;
l2capCID : LONGINT;
l2capConfReqReceived : BOOLEAN;
l2capOpen : BOOLEAN;
rfcommOpen : BOOLEAN;
channelList : ARRAY 62 OF Channel;
ok : BOOLEAN;
PROCEDURE &Init*(l2capLayer : BluetoothL2CAP.L2CAP);
VAR
result : LONGINT;
controlChannel : ControlChannel;
i : LONGINT;
BEGIN
NEW(controlChannel,SELF,i);
channelList[0] := controlChannel;
FOR i := 1 TO 61 DO
NEW(channelList[i],SELF,i);
END;
SELF.l2capLayer := l2capLayer;
SetL2CAPOpen(FALSE);
SetL2CAPConfReqReceived(FALSE);
l2capLayer.EventIndication(BluetoothL2CAP.EConfigInd,L2CAPConfigIndication,result);
ASSERT(result = 0);
l2capLayer.EventIndication(BluetoothL2CAP.EDisconnectInd,L2CAPDisconnectIndication,result);
ASSERT(result = 0);
SetRFCOMMOpen(TRUE);
END Init;
PROCEDURE GetL2CAPLayer*() : BluetoothL2CAP.L2CAP;
BEGIN
RETURN l2capLayer;
END GetL2CAPLayer;
PROCEDURE Start*(bdAddr: Bluetooth.BDAddr; VAR result : LONGINT);
VAR
status : LONGINT;
inMTU, outFlushTO : LONGINT;
outFlow,linkTO : LONGINT;
ok : BOOLEAN;
BEGIN
l2capLayer.Connect(BluetoothL2CAP.psmRFCOMM,bdAddr,l2capCID,result,status);
IF (result # 0) THEN
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Start: L2CAP connection failed. result = "); KernelLog.Hex(result,-2);
KernelLog.Ln();
END;
ELSE
inMTU := Bluetooth.MaxACLDataLen;
outFlushTO := 0FFFFH;
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Start: configure L2CAP channel: MTU = "); KernelLog.Int(inMTU,0);
KernelLog.String(" Flow = "); KernelLog.Int(outFlow,0);
KernelLog.String(" FlushTo = "); KernelLog.Int(outFlushTO,0);
KernelLog.String(" ...");
KernelLog.Ln;
END;
l2capLayer.Configure(l2capCID,inMTU,outFlow,outFlushTO,linkTO,result);
IF (result # 0) THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Start: L2CAP configuration failed. result = "); KernelLog.Hex(result,-2);
KernelLog.Ln();
ELSE
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Start: configuration done. result = "); KernelLog.Hex(result,-2);
KernelLog.String(" MTU = "); KernelLog.Int(inMTU,0);
KernelLog.String(" Flow = "); KernelLog.Int(outFlow,0);
KernelLog.String(" FlushTo = "); KernelLog.Int(outFlushTO,0);
KernelLog.Ln;
END;
ok := W4L2CAPConfReqReceived();
IF(ok) THEN
SetL2CAPOpen(TRUE);
channelList[0].SendSABM();
ELSE
result := -1;
END;
END;
END;
END Start;
PROCEDURE Close*(VAR result : LONGINT);
VAR i : LONGINT;
BEGIN
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Close: ...");
KernelLog.Ln;
END;
IF ~rfcommOpen THEN
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Close: already close");
KernelLog.Ln;
END;
RETURN;
END;
FOR i:= 0 TO 61 DO
channelList[i].SendDISC();
channelList[i].Close();
END;
result := 0;
IF(l2capOpen) THEN
l2capLayer.Disconnect(l2capCID,result);
IF (result # 0) THEN
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Close: l2capLayer.Disconnect failed. result = "); KernelLog.Hex(result,-2);
KernelLog.Ln();
END;
END;
SetL2CAPOpen(FALSE);
SetL2CAPConfReqReceived(FALSE);
END;
l2capLayer.Close;
SetRFCOMMOpen(FALSE);
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.Close: done. result = "); KernelLog.Int(result,0);
KernelLog.Ln;
END;
END Close;
PROCEDURE EstablishChannel*(serverChannel : LONGINT; VAR result : LONGINT);
VAR
state : LONGINT;
BEGIN
channelList[serverChannel * 2].SendSABM();
state := channelList[serverChannel * 2].W4State(CONNECTED);
IF state = CONNECTED THEN
result := 0;
ELSE
result := -1;
END;
END EstablishChannel;
PROCEDURE ReleaseChannel*(serverChannel : LONGINT; VAR result : LONGINT);
VAR
state : LONGINT;
BEGIN
channelList[serverChannel*2].SendDISC();
state := channelList[serverChannel * 2].W4State(DISCONNECTED);
IF state = DISCONNECTED THEN
result := 0;
ELSE
result := -1;
END;
END ReleaseChannel;
PROCEDURE SendInformation*(serverChannel : LONGINT; info : ARRAY OF CHAR; infoLength : LONGINT);
VAR
result : LONGINT;
BEGIN
channelList[serverChannel * 2].Sender(info,0,infoLength,TRUE,result);
END SendInformation;
PROCEDURE ReceiveInformation*(serverChannel : LONGINT; VAR info : ARRAY OF CHAR; VAR infoLength : LONGINT);
VAR
result : LONGINT;
BEGIN
channelList[serverChannel * 2].Receiver(info,0,LEN(info),1,infoLength,result);
END ReceiveInformation;
PROCEDURE GetSender*(serverChannel : LONGINT) : Streams.Sender;
BEGIN
RETURN channelList[serverChannel * 2].Sender;
END GetSender;
PROCEDURE GetReceiver*(serverChannel : LONGINT) : Streams.Receiver;
BEGIN
RETURN channelList[serverChannel * 2].Receiver;
END GetReceiver;
PROCEDURE SetRFCOMMOpen(state : BOOLEAN);
BEGIN {EXCLUSIVE}
rfcommOpen := state;
END SetRFCOMMOpen;
PROCEDURE SetL2CAPConfReqReceived(state : BOOLEAN);
BEGIN {EXCLUSIVE}
l2capConfReqReceived := state;
END SetL2CAPConfReqReceived;
PROCEDURE W4L2CAPConfReqReceived() : BOOLEAN;
BEGIN {EXCLUSIVE}
AWAIT(l2capConfReqReceived OR ~rfcommOpen);
IF(rfcommOpen) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END W4L2CAPConfReqReceived;
PROCEDURE SetL2CAPOpen(state: BOOLEAN);
BEGIN {EXCLUSIVE}
l2capOpen := state;
END SetL2CAPOpen;
PROCEDURE W4L2CAPOpen() : BOOLEAN;
BEGIN {EXCLUSIVE}
AWAIT(l2capOpen OR ~rfcommOpen);
IF(rfcommOpen) THEN
RETURN TRUE;
ELSE
RETURN FALSE;
END;
END W4L2CAPOpen;
PROCEDURE L2CAPConnectIndication(indication: BluetoothL2CAP.Indication);
BEGIN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.L2CAPConnectIndication: ignore!");
KernelLog.Ln;
END L2CAPConnectIndication;
PROCEDURE L2CAPDisconnectIndication(indication: BluetoothL2CAP.Indication);
VAR
result : LONGINT;
BEGIN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.L2CAPDisconnectIndication: shutdown RFCOMM");
KernelLog.Ln;
Close(result);
END L2CAPDisconnectIndication;
PROCEDURE L2CAPConfigIndication(inParam : BluetoothL2CAP.Indication);
VAR
result : LONGINT;
BEGIN
WITH inParam : BluetoothL2CAP.ConfigInd DO
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.L2CAPConfigIndication: ..."); KernelLog.Ln;
KernelLog.String("cid = "); KernelLog.Int(inParam.c.sid,0);
KernelLog.String(" ident = "); KernelLog.Int(ORD(inParam.ident),0);
KernelLog.String(" MTU = "); KernelLog.Int(inParam.outMTU,0);
KernelLog.String(" FlushTO = "); KernelLog.Int(inParam.inFlushTO,0);
KernelLog.Ln;
END;
l2capLayer.ConfigurationResponse(inParam.c.sid,inParam.ident,inParam.outMTU,
inParam.inFlushTO,result);
END;
SetL2CAPConfReqReceived(TRUE);
END L2CAPConfigIndication;
PROCEDURE SendFrame(frame : ARRAY OF CHAR;length : LONGINT);
VAR
size : LONGINT;
result : LONGINT;
i : LONGINT;
BEGIN
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.SendFrame: data size = "); KernelLog.Int(length,0);
KernelLog.Ln;
FOR i := 0 TO length-1 DO
KernelLog.Hex(ORD(frame[i]), -2); KernelLog.String(" " );
END;
KernelLog.Ln;
END;
IF(l2capOpen = TRUE) THEN
l2capLayer.Write(l2capCID,0,length,frame,size,result);
END;
IF (result # 0) THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.SendFrame: l2cap.Write failed. result = "); KernelLog.Int(result,0);
KernelLog.Ln;
END;
END SendFrame;
PROCEDURE ReceiveFrame;
VAR
buffer : ARRAY 512 OF CHAR;
i : LONGINT;
result,size : LONGINT;
frameType : LONGINT;
dlci : LONGINT;
BEGIN
REPEAT
l2capLayer.Read(l2capCID,LEN(buffer),buffer,result,size);
IF (result = 0) THEN
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.ReceiveFrame: data size = "); KernelLog.Int(size,0);
KernelLog.Ln;
FOR i := 0 TO size-1 DO
KernelLog.Hex(ORD(buffer[i]), -2); KernelLog.String(" " );
END;
KernelLog.Ln;
END;
dlci := ORD(buffer[0]) DIV 4;
frameType := BITLAND(ORD(buffer[1]),0EFH);
IF (frameType = SABMFRAME) THEN
channelList[dlci].ReceiveSABM();
ELSIF(frameType = UAFRAME) THEN
channelList[dlci].ReceiveUA();
ELSIF(frameType = DMFRAME) THEN
channelList[dlci].ReceiveDM();
ELSIF(frameType = DISCFRAME) THEN
channelList[dlci].ReceiveDISC();
ELSIF(frameType = UIHFRAME) THEN
channelList[dlci].ReceiveUIH(buffer,size);
ELSE
KernelLog.String("unknown frame! "); KernelLog.Hex(frameType,-2);
KernelLog.String(" DLCI = "); KernelLog.Hex(dlci,-2);
KernelLog.Ln;
END;
ELSE
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM.ReceiveFrame: l2cap.Read failed. result = "); KernelLog.Int(result,0);
KernelLog.Ln;
END;
UNTIL (result # 0);
END ReceiveFrame;
BEGIN {ACTIVE}
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM: {ACTIVE} ...");
KernelLog.Ln;
END;
ok := W4L2CAPOpen();
IF(ok) THEN
ReceiveFrame();
END;
IF TraceRFCOMM THEN
KernelLog.String(ModuleName);
KernelLog.String("RFCOMM: {ACTIVE} done.");
KernelLog.Ln;
END;
END RFCOMM;
VAR
crcTable: ARRAY 256 OF CHAR;
PROCEDURE CreateCRCTable;
VAR
i,j : LONGINT;
pol,data,sr : CHAR;
op1,op2,op3 : CHAR;
BEGIN
pol := CHR(224);
FOR j := 0 TO 255 DO
sr := CHR(0);
data := CHR(j);
FOR i := 0 TO 7 DO
op1 := BITCAND(data,CHR(1));
op2 := BITCAND(sr,CHR(1));
op3 := BITCXOR(op1,op2);
sr := CHR(ORD(sr) DIV 2);
IF (op3 #CHR( 0)) THEN
sr := BITCXOR(sr,pol);
END;
data := CHR(ORD(data) DIV 2);
sr := BITCAND(sr,CHR(255));
END;
crcTable[j] := sr;
END;
END CreateCRCTable;
PROCEDURE BITLOR(x, y: LONGINT): LONGINT;
BEGIN RETURN S.VAL(LONGINT, S.VAL(SET, x) + S.VAL(SET, y))
END BITLOR;
PROCEDURE BITCAND(x, y: CHAR): CHAR;
BEGIN RETURN CHR(S.VAL(LONGINT, S.VAL(SET, LONG(ORD(x))) * S.VAL(SET, LONG(ORD(y)))))
END BITCAND;
PROCEDURE BITCXOR(x, y: CHAR): CHAR;
BEGIN RETURN CHR(S.VAL(LONGINT, S.VAL(SET, LONG(ORD(x))) / S.VAL(SET, LONG(ORD(y)))))
END BITCXOR;
PROCEDURE BITLAND(x, y: LONGINT): LONGINT;
BEGIN RETURN S.VAL(LONGINT, S.VAL(SET, x) * S.VAL(SET, y))
END BITLAND;
BEGIN
CreateCRCTable();
END BluetoothRFCOMM.