MODULE BluetoothHCI;
IMPORT KernelLog, Bluetooth;
CONST
Trace = FALSE;
TraceReceive = FALSE;
TraceSend = FALSE;
ModuleName = "[BTHCI]";
TraceHCI = FALSE;
TraceLink = FALSE;
Timeout = 1000;
ConnectionTimeout = 10000;
ogfLinkControl* = 01H;
ocfInquiry* = 0001H;
ocfInquiryCancel* = 0002H;
ocfPeriodicInquiryMode* = 0003H;
ocfExitPeriodicInquiryMode* = 0004H;
ocfCreateConnection* = 0005H;
ocfDisconnect* = 0006H;
ocfAddSCOConnection* = 0007H;
ocfAcceptConnectionRequest* = 0009H;
ocfRejectConnectionRequest* = 000AH;
ocfLinkKeyRequestReply* = 000BH;
ocfLinkKeyRequestNegativeReply* = 000CH;
ocfPINCodeRequestReply* = 000DH;
ocfPINCodeRequestNegativeReply* = 000EH;
ocfChangeConnectionPacketType* = 000FH;
ocfAuthenticationRequested* = 0011H;
ocfSetConnectionEncryption* = 0013H;
ocfChangeConnectionLinkKey* = 0015H;
ocfMasterLinkKey* = 0017H;
ocfRemoteNameRequest* = 0019H;
ocfReadRemoteSupportedFeatures* = 001BH;
ocfReadRemoteVersionInformation* = 001DH;
ocfReadClockOffset* = 001FH;
ogfLinkPolicy* = 02H;
ocfHoldMode* = 0001H;
ocfSniffMode* = 0003H;
ocfExitSniffMode* = 0004H;
ocfParkMode* = 0005H;
ocfExitParkMode* = 0006H;
ocfQoSSetup* = 0007H;
ocfRoleDiscovery* = 0009H;
ocfSwitchRole* = 000BH;
ocfReadLinkPolicySettings* = 000CH;
ocfWriteLinkPolicySettings* = 000DH;
ogfControl* = 03H;
ocfSetEventMask* = 0001H;
ocfReset* = 0003H;
ocfSetEventFilter* = 0005H;
ocfFlush* = 0008H;
ocfReadPINType* = 0009H;
ocfWritePINType* = 000AH;
ocfCreateNewUnitKey* = 000BH;
ocfReadStoredLinkKey* = 000DH;
ocfWriteStoredLinkKey* = 0011H;
ocfDeleteStoredLinkKey* = 0012H;
ocfChangeLocalName* = 0013H;
ocfReadLocalName* = 0014H;
ocfReadConnectionAcceptTimeout* = 0015H;
ocfWriteConnectionAcceptTimeout* = 0016H;
ocfReadPageTimeout* = 0017H;
ocfWritePageTimeout* = 0018H;
ocfReadScanEnable* = 0019H;
ocfWriteScanEnable* = 001AH;
ocfReadPageScanActivity* = 001BH;
ocfWritePageScanActivity* = 001CH;
ocfReadInquiryScanActivity* = 001DH;
ocfWriteInquiryScanActivity* = 001EH;
ocfReadAuthenticationEnable* = 001FH;
ocfWriteAuthenticationEnable* = 0020H;
ocfReadEncryptionMode* = 0021H;
ocfWriteEncryptionMode* = 0022H;
ocfReadClassOfDevice* = 0023H;
ocfWriteClassOfDevice* = 0024H;
ocfReadVoiceSetting* = 0025H;
ocfWriteVoiceSetting* = 0026H;
ocfReadAutomaticFlushTimeout* = 0027H;
ocfWriteAutomaticFlushTimeout* = 0028H;
ocfReadNumBroadcastRetrans* = 0029H;
ocfWriteNumBroadcastRetrans* = 002AH;
ocfReadHoldModeActivity* = 002BH;
ocfWriteHoldModeActivity* = 002CH;
ocfReadTransmitPowerLevel* = 002DH;
ocfReadSCOFlowControlEnable* = 002EH;
ocfWriteSCOFlowControlEnable* = 002FH;
ocfSetHostCtrlToHostFlowCtrl* = 0031H;
ocfHostBufferSize* = 0033H;
ocfHostNumberOfCompletedPackets* = 0035H;
ocfReadLinkSupervisionTimeout* = 0036H;
ocfWriteLinkSupervisionTimeout* = 0037H;
ocfReadNumberOfSupportedIAC* = 0038H;
ocfReadCurrentIACLAP* = 0039H;
ocfWriteCurrentIACLAP* = 003AH;
ocfReadPageScanPeriodMode* = 003BH;
ocfWritePageScanPeriodMode* = 003CH;
ocfReadPageScanMode* = 003DH;
ocfWritePageScanMode* = 003EH;
ogfInformational* = 04H;
ocfReadLocalVersionInformation* = 0001H;
ocfReadLocalSupportedFeatures* = 0003H;
ocfReadBufferSize* = 0005H;
ocfReadCountryCode* = 0007H;
ocfReadBDAddr* = 0009H;
ogfStatus* = 05H;
ocfReadFailedContactCounter* = 0001H;
ocfResetFailedContactCounter* = 0002H;
ocfGetLinkQuality* = 0003H;
ocfHCIReadRSSI* = 0005H;
ogfEricsson* = 03FH;
ocfSetUARTBaudRate* = 0009H;
pbfFirst* = 2;
pbfContinuing* = 1;
bfPointToPoint* = 0;
bfActive* = 1;
bfPiconet* = 2;
EInquiryComplete* = 01X;
EInquiryResult* = 02X;
EConnectionComplete* = 03X;
EDisconnectionComplete* = 05X;
EReadRemoteVersionInfoComplete* = 0CX;
ECmdComplete* = 0EX;
ECmdStatus* = 0FX;
ENofCompletedPackets* = 13X;
EMaxSlotsChange* = 1BX;
EPageScanRepModeChange* = 20X;
CONST
SENoScan* = 00X;
SEInquiry* = 01X;
SEPage* = 02X;
SEInquiryPage* = 03X;
EFClear* = 00X;
EFInquiryResult* = 01X;
EFConnectionSetup* = 02X;
EFIRNewDevice* = 00X;
EFIRClass* = 01X;
EFIRAddr* = 02X;
EFCSAll* = 00X;
EFCSClass* = 01X;
EFCSAddr* = 02X;
EFCSAAOff* = 01X;
EFCSAAOn* = 02X;
EFCSAAOnRoleSwitch* = 03X;
CONST
lsUp* = 0;
lsDown* = 1;
TYPE
Link* = OBJECT
VAR
next: Link;
hci : HCI;
state*: LONGINT;
remote*: Bluetooth.BDAddr;
handle-: LONGINT;
type*: LONGINT;
encryption*: LONGINT;
reason*: LONGINT;
nofPackets-: LONGINT;
OnReceiveACLData*: ReceiveACLDataEvent;
PROCEDURE &Init*(hci : HCI; remote: Bluetooth.BDAddr; handle: LONGINT);
BEGIN
ASSERT((0000H <= handle) & (handle <= 0EFFH));
SELF.hci := hci; SELF.remote := remote; SELF.handle := handle;
IF TraceLink THEN
KernelLog.String(ModuleName);
KernelLog.String("Link.Init: handle = "); KernelLog.Int(handle,0);
KernelLog.Ln;
END;
END Init;
PROCEDURE SendACL*(PBF, BF: LONGINT; VAR data: ARRAY OF CHAR; ofs, len: LONGINT): LONGINT;
VAR v, res: LONGINT; aclhdr: ARRAY 4 OF CHAR;
BEGIN
ASSERT((pbfContinuing <= PBF) & (PBF <= pbfFirst));
ASSERT((bfPointToPoint <= BF) & (BF <= bfPiconet));
ASSERT((0 < len) & (len < 10000H));
v := handle + PBF*1000H + BF*4000H;
aclhdr[0] := CHR(v MOD 100H); aclhdr[1] := CHR(v DIV 100H);
aclhdr[2] := CHR(len MOD 100H); aclhdr[3] := CHR(len DIV 100H);
hci.tl.Send1H(Bluetooth.ACL, aclhdr, 4, data, ofs, len, res);
IF TraceLink THEN
KernelLog.String(ModuleName);
KernelLog.String("Link.SendACL: handle = "); KernelLog.Int(handle,0);
KernelLog.Ln;
END;
RETURN res
END SendACL;
PROCEDURE SendACLH*(PBF, BF: LONGINT; VAR hdr: ARRAY OF CHAR; hdrlen: LONGINT; VAR data: ARRAY OF CHAR; ofs, len: LONGINT): LONGINT;
VAR v, res, totlen: LONGINT; aclhdr: ARRAY 4 OF CHAR;
BEGIN
totlen := len + hdrlen;
ASSERT((pbfContinuing <= PBF) & (PBF <= pbfFirst));
ASSERT((bfPointToPoint <= BF) & (BF <= bfPiconet));
ASSERT((0 < totlen) & (totlen < 10000H));
v := handle + PBF*1000H + BF*4000H;
aclhdr[0] := CHR(v MOD 100H); aclhdr[1] := CHR(v DIV 100H);
aclhdr[2] := CHR(totlen MOD 100H); aclhdr[3] := CHR(totlen DIV 100H);
hci.tl.Send2H(Bluetooth.ACL, aclhdr, 4, hdr, hdrlen, data, ofs, len, res);
IF TraceLink THEN
KernelLog.String(ModuleName);
KernelLog.String("Link.SendACLH: handle = "); KernelLog.Int(handle,0);
KernelLog.Ln;
END;
RETURN res
END SendACLH;
PROCEDURE ACLDataReceived(acl: Bluetooth.ACLPacket);
BEGIN
IF TraceLink THEN
KernelLog.String(ModuleName);
KernelLog.String("Link.ACLDataReceived: handle = "); KernelLog.Int(handle,0);
KernelLog.Ln;
END;
IF (OnReceiveACLData # NIL) THEN OnReceiveACLData(SELF, acl) END
END ACLDataReceived;
END Link;
ReceiveACLDataEvent* = PROCEDURE {DELEGATE} (sender: Link; acl: Bluetooth.ACLPacket);
LinkEnumPar = POINTER TO RECORD
handle: LONGINT;
remote: Bluetooth.BDAddr;
link: Link
END;
LinkEnumerator* = PROCEDURE {DELEGATE} (l: Link; par: ANY): BOOLEAN;
LinkManager = OBJECT
VAR
links: Link;
numLinks: LONGINT;
PROCEDURE &Init*;
BEGIN
NEW(links, NIL,"", 0);
links.handle := -1;
numLinks := 0
END Init;
PROCEDURE Reset;
BEGIN
links.next := NIL;
numLinks := 0
END Reset;
PROCEDURE AddLink*(l: Link);
BEGIN {EXCLUSIVE}
l.next := links.next; links.next := l; INC(numLinks)
END AddLink;
PROCEDURE RemoveLink*(l: Link);
VAR p,q: Link;
BEGIN {EXCLUSIVE}
p := links.next; q := links;
WHILE (p # NIL) & (p # l) DO q := p; p := p.next END;
IF (p # NIL) THEN q.next := p.next; DEC(numLinks) END
END RemoveLink;
PROCEDURE FindLink*(handle: LONGINT): Link;
VAR l: Link;
BEGIN {EXCLUSIVE}
l := links.next;
WHILE (l # NIL) & (l.handle # handle) DO l := l.next END;
RETURN l
END FindLink;
PROCEDURE Enumerate(callback: LinkEnumerator; par: ANY);
VAR l: Link; la: POINTER TO ARRAY OF Link; i: LONGINT;
BEGIN
NEW(la, numLinks);
BEGIN {EXCLUSIVE}
l := links.next;
FOR i := 0 TO numLinks-1 DO la[i] := l; l := l.next END
END;
i := 0;
WHILE (i < numLinks) & (callback(la[i], par)) DO
INC(i)
END
END Enumerate;
END LinkManager;
HCI* = OBJECT
VAR
tl: Bluetooth.TransportLayer;
aclQueue, eventQueue-: Bluetooth.Queue;
linkManager*: LinkManager;
bdAddr-: Bluetooth.BDAddr;
aclMTU-, scoMTU-, aclNumPackets-, scoNumPackets-: LONGINT;
OnConnectionComplete* : ConnectionComplete;
OnDisconnectionComplete* : DisconnectionComplete;
OnInquiryComplete* : InquiryComplete;
OnConnect*: ConnectionEvent;
OnDisconnect*: ConnectionEvent;
OnInquiry*: InquiryEvent;
OnEvent*: GeneralEvent;
OnError*: ErrorEvent;
PROCEDURE &Init*(transportLayer: Bluetooth.TransportLayer);
VAR q: Bluetooth.Queue;
BEGIN
tl := transportLayer;
NEW(linkManager);
NEW(eventQueue); tl.SetSink(Bluetooth.Event, eventQueue);
eventQueue.RegisterPacketFilter(EricssonFilter, EricssonHandler);
eventQueue.RegisterPacketFilter(EventFilter, EventHandler);
NEW(aclQueue); tl.SetSink(Bluetooth.ACL, aclQueue);
aclQueue.RegisterPacketFilter(ACLFilter, ACLHandler);
q := tl.GetSink(Bluetooth.Default);
q.RegisterPacketFilter(ErrorFilter, ErrorHandler);
END Init;
PROCEDURE Close*;
BEGIN {EXCLUSIVE}
IF TraceHCI THEN
KernelLog.String(ModuleName); KernelLog.String("HCI.Close: ...");
KernelLog.Ln;
END;
tl.Close;
eventQueue.Close; aclQueue.Close;
IF TraceHCI THEN
KernelLog.String(ModuleName); KernelLog.String("HCI.Close: done.");
KernelLog.Ln;
END;
END Close;
PROCEDURE Initialize*(): LONGINT;
VAR res: LONGINT;
BEGIN
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.Initialize: ...");
KernelLog.Ln;
END;
res := Reset();
IF (res # 0) THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.Initialize: Reset failed. res = 0x"); KernelLog.Hex(res,-2);
KernelLog.Ln;
RETURN res
END;
res := ReadBDAddr(bdAddr);
IF (res # 0) THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.Initialize: ReadBDaddr failed. res = 0x"); KernelLog.Hex(res,-2);
KernelLog.Ln;
RETURN res
END;
res := ReadBufferSize(aclMTU, scoMTU, aclNumPackets, scoNumPackets);
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.Initialize: done. ReadBufferSize res = "); KernelLog.Int(res,0);
KernelLog.Ln;
END;
RETURN res;
END Initialize;
PROCEDURE EnumerateLinks*(enumCallback: LinkEnumerator; par: ANY);
BEGIN
linkManager.Enumerate(enumCallback, par)
END EnumerateLinks;
PROCEDURE FindLinkCallback(l: Link; par: ANY): BOOLEAN;
BEGIN
WITH par: LinkEnumPar DO
IF (par.handle # -1) THEN
IF (par.handle = l.handle) THEN par.link := l END
ELSE
IF (par.remote = l.remote) THEN par.link := l END
END;
RETURN par.link = NIL
END
END FindLinkCallback;
PROCEDURE FindLink*(handle: LONGINT; remote: Bluetooth.BDAddr): Link;
VAR lep: LinkEnumPar;
BEGIN
NEW(lep); lep.handle := handle; lep.remote := remote; lep.link := NIL;
linkManager.Enumerate(FindLinkCallback, lep);
RETURN lep.link
END FindLink;
PROCEDURE SendCommand*(OGF, OCF: LONGINT; params: ARRAY OF CHAR; len: LONGINT;
VAR packet: Bluetooth.EventPacket;
VAR pending: BOOLEAN;
VAR res: LONGINT);
BEGIN {EXCLUSIVE}
InSendCommand(OGF, OCF, params, len, packet, pending, res)
END SendCommand;
PROCEDURE InSendCommand(OGF, OCF: LONGINT; params: ARRAY OF CHAR; len: LONGINT;
VAR packet: Bluetooth.EventPacket;
VAR pending: BOOLEAN;
VAR res: LONGINT);
VAR
cmd: POINTER TO ARRAY OF CHAR; i: LONGINT;
BEGIN
NEW(cmd,3+len);
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.InSendCommand: OGF= 0x"); KernelLog.Hex(OGF,-2);
KernelLog.String(" OCF= 0x"); KernelLog.Hex(OCF,-2);
KernelLog.String(" params= ");
FOR i := 0 TO len-1 DO
KernelLog.String("0x"); KernelLog.Hex(ORD(params[i]), -2);
END;
KernelLog.String(" ..."); KernelLog.Ln;
END;
pending := FALSE;
ComposeCommandHeader(OGF, OCF, len, cmd^);
FOR i := 0 TO len-1 DO cmd[3+i] := params[i] END;
tl.Send(Bluetooth.Command, cmd^, 0, 3+len, res);
IF (res = 0) THEN
GetEvent(Timeout,packet,res);
IF (res = 0) THEN
IF (packet.code = ECmdComplete) & (packet.paramLen >= 3) &
(packet.params[1] = cmd[0]) & (packet.params[2] = cmd[1]) THEN
res := ORD(packet.params[3]);
IF (OGF = ogfControl) & (OCF = ocfReset) & (res = 0) THEN
linkManager.Reset
END;
ELSIF (packet.code = ECmdStatus) & (packet.paramLen >= 3) &
(packet.params[2] = cmd[0]) & (packet.params[3] = cmd[1]) THEN
res := ORD(packet.params[0]);
pending := TRUE;
ELSE
res := Bluetooth.ErrInvalidEvent;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.InSendCommand: invalid event received:"); KernelLog.Ln;
KernelLog.String(" event code: "); KernelLog.Hex(ORD(packet.code), -2); KernelLog.Ln;
KernelLog.String(" parameters: ");
FOR i := 0 TO packet.paramLen-1 DO
KernelLog.Hex(ORD(packet.params[i]), -2); KernelLog.Char(" ")
END;
KernelLog.Ln;
END;
END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.InSendCommand: event received. event code = 0x"); KernelLog.Hex(ORD(packet.code), -2);
KernelLog.String(" result = 0x"); KernelLog.Hex(res,-2);
KernelLog.String(" pending = "); IF pending THEN KernelLog.String("TRUE"); ELSE KernelLog.String("FALSE"); END;
KernelLog.Ln;
END;
ELSE
KernelLog.String(ModuleName);
KernelLog.String("HCI.InSendCommand: GetEvent failed. res = 0x"); KernelLog.Hex(res,-2);
KernelLog.Ln;
END;
ELSE
KernelLog.String(ModuleName);
KernelLog.String("HCI.InSendCommand: tl.Send failed. res = 0x"); KernelLog.Hex(res,-2);
KernelLog.Ln;
END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.InSendCommand: done.");
KernelLog.Ln;
END;
END InSendCommand;
PROCEDURE GetEvent*(timeout: LONGINT; VAR event: Bluetooth.EventPacket; VAR res: LONGINT);
VAR p: Bluetooth.Packet;
BEGIN
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.GetEvent: ...");
KernelLog.Ln;
END;
eventQueue.Get(p, timeout, res);
IF (res = 0) THEN
IF (p IS Bluetooth.EventPacket) THEN
event := p(Bluetooth.EventPacket);
ELSE
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.GetEvent: wrong packet received");
KernelLog.Ln;
END;
res := Bluetooth.ErrInvalidPacket;
END
ELSE
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.GetEvent: eventQueue.Get failed. res = 0x"); KernelLog.Hex(res,-2);
KernelLog.Ln;
END;
END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.GetEvent: done.");
KernelLog.Ln;
END;
END GetEvent;
PROCEDURE Inquiry*(lap : LONGINT;inquiryLength : LONGINT; numResponses : LONGINT) : LONGINT;
VAR
par: ARRAY 5 OF CHAR;
event: Bluetooth.EventPacket;
pending: BOOLEAN;
res: LONGINT;
BEGIN
par[0] := CHR(lap MOD 100H);
par[1] := CHR((lap DIV 100H) MOD 100H);
par[2] := CHR(lap DIV 10000H);
par[3] := CHR(inquiryLength);
par[4] := CHR(numResponses);
InSendCommand(ogfLinkControl,ocfInquiry,par,5,event,pending,res);
RETURN res;
END Inquiry;
PROCEDURE CreateConnection*(bdAddr: Bluetooth.BDAddr; clkofs: LONGINT): LONGINT;
VAR
par: ARRAY 13 OF CHAR;
event: Bluetooth.EventPacket;
pending: BOOLEAN;
i, res: LONGINT;
BEGIN
FOR i := 0 TO Bluetooth.BDAddrLen-1 DO par[i] := bdAddr[i] END;
par[6] := 08X; par[7] := 00X;
par[8] := 00X;
par[9] := 00X;
par[10] := CHR(clkofs MOD 100H); par[11] := CHR(clkofs DIV 100H MOD 100H);
par[12] := 00X;
InSendCommand(ogfLinkControl, ocfCreateConnection, par, 13, event, pending, res);
RETURN res
END CreateConnection;
PROCEDURE Disconnect*(linkHandle,reason : LONGINT) : LONGINT;
VAR
par: ARRAY 3 OF CHAR;
event: Bluetooth.EventPacket;
pending: BOOLEAN;
res: LONGINT;
BEGIN
par[0] := CHR(linkHandle MOD 100H);
par[1] := CHR(linkHandle DIV 100H);
par[2] := CHR(reason);
InSendCommand(ogfLinkControl,ocfDisconnect,par,3,event,pending, res);
RETURN res;
END Disconnect;
PROCEDURE SetEventMask*(eventMask : LONGINT) : LONGINT;
VAR
par : ARRAY 8 OF CHAR;
res: LONGINT;
event: Bluetooth.EventPacket;
pending: BOOLEAN;
BEGIN
par[0] := CHR(eventMask MOD 100H); eventMask := eventMask DIV 100H;
par[1] := CHR(eventMask MOD 100H); eventMask := eventMask DIV 100H;
par[2] := CHR(eventMask MOD 100H); eventMask := eventMask DIV 100H;
par[3] := CHR(eventMask);
InSendCommand(ogfControl, ocfSetEventMask, par, 8, event, pending, res);
RETURN res;
END SetEventMask;
PROCEDURE Reset*(): LONGINT;
VAR
pending: BOOLEAN;
event: Bluetooth.EventPacket;
res: LONGINT;
BEGIN
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.Reset: ..."); KernelLog.Ln;
END;
eventQueue.Clear;
InSendCommand(ogfControl, ocfReset, "", 0, event, pending, res);
IF pending & (res = 0) THEN res := Bluetooth.Error END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.Reset: done. res = "); KernelLog.Int(res,0); KernelLog.Ln;
END;
RETURN res
END Reset;
PROCEDURE SetEventFilter*(type, conditionType: CHAR; condition: ARRAY OF CHAR): LONGINT;
VAR
par: ARRAY 9 OF CHAR;
i, len, res: LONGINT;
event: Bluetooth.EventPacket;
pending: BOOLEAN;
BEGIN
res := Bluetooth.ErrInvalidParameters;
CASE type OF
| EFClear: len := 1
| EFInquiryResult:
CASE conditionType OF
| EFIRNewDevice: len := 2
| EFIRClass: len := 8
| EFIRAddr: len := 8
ELSE RETURN res
END
| EFConnectionSetup:
CASE conditionType OF
| EFCSAll: len := 3
| EFCSClass: len := 9
| EFCSAddr: len := 9
ELSE RETURN res
END
ELSE RETURN res
END;
par[0] := type;
par[1] := conditionType;
FOR i := 0 TO len-3 DO par[2+i] := condition[i] END;
InSendCommand(ogfControl, ocfSetEventFilter, par, len, event, pending, res);
IF pending & (res = 0) THEN res := Bluetooth.Error END;
RETURN res
END SetEventFilter;
PROCEDURE WriteScanEnable*(mode: CHAR): LONGINT;
VAR
par: ARRAY 1 OF CHAR;
pending: BOOLEAN;
event: Bluetooth.EventPacket;
res: LONGINT;
BEGIN
par[0] := mode;
InSendCommand(ogfControl, ocfWriteScanEnable, par, 1, event, pending, res);
IF pending & (res = 0) THEN res := Bluetooth.Error END;
RETURN res
END WriteScanEnable;
PROCEDURE ReadScanEnable*(VAR scanEnable : CHAR) : LONGINT;
VAR
pending: BOOLEAN;
event: Bluetooth.EventPacket;
res : LONGINT;
BEGIN
InSendCommand(ogfControl,ocfReadScanEnable,"",0,event,pending,res);
scanEnable := event.params[4];
IF pending & (res = 0) THEN res := Bluetooth.Error END;
RETURN res;
END ReadScanEnable;
PROCEDURE WriteLinkSupervisionTimeout*(inHandle, linkTimeout : LONGINT) : LONGINT;
VAR
par: ARRAY 4 OF CHAR;
pending: BOOLEAN;
event: Bluetooth.EventPacket;
res : LONGINT;
outHandle : LONGINT;
BEGIN
par[0] := CHR(inHandle MOD 100H);
par[1] := CHR(inHandle DIV 100H);
par[2] := CHR(linkTimeout MOD 100H);
par[3] := CHR(linkTimeout DIV 100H);
InSendCommand(ogfControl,ocfWriteLinkSupervisionTimeout,par,4,event,pending,res);
IF pending THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.WriteLinkSupervisonTimout: pending! - res = "); KernelLog.Int(res,0);
KernelLog.Ln;
res := Bluetooth.ErrInvalidEvent;
ELSIF (res = 0) THEN
outHandle := (ORD(event.params[4]) + ORD(event.params[5]) * 100H) MOD 1000H;
IF(outHandle # inHandle) THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.WriteLinkSupervisonTimout: error ?! - outHandle = "); KernelLog.Int(outHandle,0);
KernelLog.String("; inHandle = "); KernelLog.Int(inHandle,0);
KernelLog.Ln;
END;
END;
RETURN res;
END WriteLinkSupervisionTimeout;
PROCEDURE ReadLinkSupervisionTimeout*(inHandle : LONGINT; VAR linkTimeout : LONGINT) : LONGINT;
VAR
par: ARRAY 2 OF CHAR;
pending: BOOLEAN;
event: Bluetooth.EventPacket;
res : LONGINT;
outHandle : LONGINT;
BEGIN
par[0] := CHR(inHandle MOD 100H);
par[1] := CHR(inHandle DIV 100H);
InSendCommand(ogfControl,ocfReadLinkSupervisionTimeout,par,2,event,pending,res);
IF pending THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.ReadLinkSupervisonTimout: pending! - res = "); KernelLog.Int(res,0);
KernelLog.Ln;
res := Bluetooth.ErrInvalidEvent;
ELSIF (res = 0) THEN
outHandle := (ORD(event.params[4]) + ORD(event.params[5]) * 100H) MOD 1000H;
IF(outHandle # inHandle) THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.ReadLinkSupervisonTimout: error ?! - outHandle = "); KernelLog.Int(outHandle,0);
KernelLog.String("; inHandle = "); KernelLog.Int(inHandle,0);
KernelLog.Ln;
ELSE
linkTimeout := ORD(event.params[6]) + ORD(event.params[7]) * 100H;
END;
END;
RETURN res;
END ReadLinkSupervisionTimeout;
PROCEDURE EricssonSetUARTBaudRate*(baudRate : CHAR):LONGINT;
VAR
par: ARRAY 1 OF CHAR;
pending: BOOLEAN;
event: Bluetooth.EventPacket;
res : LONGINT;
BEGIN
par[0] := baudRate;
InSendCommand(ogfEricsson,ocfSetUARTBaudRate,par,LEN(par),event,pending,res);
IF pending THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EricssonSetUARTBaudRate: pending! - res = "); KernelLog.Int(res,0);
KernelLog.Ln;
END;
IF pending & (res = 0) THEN res := Bluetooth.Error END;
RETURN res;
END EricssonSetUARTBaudRate;
PROCEDURE ReadBDAddr*(VAR bdAddr: Bluetooth.BDAddr): LONGINT;
VAR
event: Bluetooth.EventPacket;
pending: BOOLEAN;
res, i: LONGINT;
BEGIN
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.ReadBDAddr: ...");
KernelLog.Ln;
END;
InSendCommand(ogfInformational, ocfReadBDAddr, "", 0, event, pending, res);
IF pending THEN res := Bluetooth.ErrInvalidEvent
ELSIF (res = 0) THEN
FOR i := 0 TO Bluetooth.BDAddrLen-1 DO bdAddr[i] := event.params[4+i] END;
END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.ReadBDAddr: done. res = "); KernelLog.Int(res,0);
KernelLog.Ln;
END;
RETURN res
END ReadBDAddr;
PROCEDURE ReadBufferSize*(VAR aclMaxLen, scoMaxLen, aclNumPackets, scoNumPackets: LONGINT): LONGINT;
VAR
event: Bluetooth.EventPacket;
pending: BOOLEAN;
res: LONGINT;
BEGIN
InSendCommand(ogfInformational, ocfReadBufferSize, "", 0, event, pending, res);
IF pending THEN res := Bluetooth.ErrInvalidEvent
ELSIF (res = 0) THEN
aclMaxLen := ORD(event.params[5])*100H+ORD(event.params[4]);
scoMaxLen := ORD(event.params[6]);
aclNumPackets := ORD(event.params[8])*100H+ORD(event.params[7]);
scoNumPackets := ORD(event.params[10])*100H+ORD(event.params[9])
END;
RETURN res
END ReadBufferSize;
PROCEDURE EventFilter(packet: Bluetooth.Packet): BOOLEAN;
VAR event: Bluetooth.EventPacket; ec: CHAR;
BEGIN
event := packet(Bluetooth.EventPacket); ec := event.code;
RETURN
(ec = EConnectionComplete)
OR (ec = EDisconnectionComplete)
OR (ec = EInquiryResult)
OR (ec = EInquiryComplete)
OR (ec = ENofCompletedPackets)
OR (ec = EMaxSlotsChange)
OR (ec = EPageScanRepModeChange)
OR
((ec = ECmdStatus) & (event.params[0] = 0X) & (event.params[2] = 0X) & (event.params[3] = 0X))
OR
((ec = ECmdComplete) & (event.params[1] = 0X) & (event.params[2] = 0X))
END EventFilter;
PROCEDURE EventHandler(packet: Bluetooth.Packet);
VAR
event: Bluetooth.EventPacket;
i : LONGINT;
BEGIN
event := packet(Bluetooth.EventPacket);
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventHandler: event.code = 0x"); KernelLog.Hex(ORD(event.code),-2);
KernelLog.String(" ..."); KernelLog.Ln;
END;
IF (event.code = EConnectionComplete) THEN
EventConnectionCompleteOLD(event);
ELSIF (event.code = EDisconnectionComplete) THEN
EventDisconnectionCompleteOLD(event);
ELSIF (event.code = EInquiryResult) THEN
EventInquiryResult(event);
ELSIF (event.code = ENofCompletedPackets) THEN
EventNumOfCompletedPackets(event);
ELSIF (event.code = EInquiryComplete) THEN
EventInquiryComplete(event);
ELSIF (event.code = EMaxSlotsChange) THEN
EventMaxSlotsChange(event);
ELSIF (event.code = EPageScanRepModeChange) THEN
EventPageScanRepModeChange(event);
ELSIF ((event.code = ECmdStatus) OR (event.code = ECmdComplete)) THEN
ELSE
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventHandler: unhandled event ! event.code = 0x");
KernelLog.Hex(ORD(event.code),-2); KernelLog.String(" params:"); KernelLog.Ln;
FOR i:= 0 TO event.paramLen-1 DO
KernelLog.Hex(ORD(event.params[i]),-2); KernelLog.String(" ");
END;
KernelLog.Ln;
END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventHandler: done."); KernelLog.Ln;
END;
END EventHandler;
PROCEDURE EventInquiryComplete(event: Bluetooth.EventPacket);
VAR
status : LONGINT;
BEGIN
status := ORD(event.params[0]);
IF (OnInquiryComplete # NIL) THEN
OnInquiryComplete(SELF,status);
END;
END EventInquiryComplete;
PROCEDURE EventInquiryResult(event: Bluetooth.EventPacket);
VAR
nr,psrm, pspm, psm, co: LONGINT;
bdAddr : Bluetooth.BDAddr;
class : Bluetooth.DeviceClass;
i,k,ofs : LONGINT;
BEGIN
IF (OnInquiry # NIL) THEN
i := 0; nr := ORD(event.params[0]);
WHILE (i < nr) DO
ofs := 1 + i*14;
FOR k := 0 TO Bluetooth.BDAddrLen-1 DO
bdAddr[k] := event.params[ofs+k]
END;
psrm := ORD(event.params[ofs+6]);
pspm := ORD(event.params[ofs+7]);
psm := ORD(event.params[ofs+8]);
FOR k := 0 TO Bluetooth.DeviceClassLen-1 DO
class[k] := event.params[ofs+9+k]
END;
co := ORD(event.params[ofs+12])+LONG(ORD(event.params[ofs+13]))*100H;
OnInquiry(SELF,bdAddr,class,psrm,pspm,psm,co);
INC(i);
END;
END;
END EventInquiryResult;
PROCEDURE EventConnectionComplete(event: Bluetooth.EventPacket);
VAR
status,handle : LONGINT;
bdAddr : Bluetooth.BDAddr;
linkType ,encryMode: LONGINT;
i : LONGINT;
BEGIN
status := ORD(event.params[0]);
handle := (ORD(event.params[2])*100H + ORD(event.params[1])) MOD 1000H;
FOR i := 0 TO Bluetooth.BDAddrLen-1 DO
bdAddr[i] := event.params[3+i]
END;
linkType := ORD(event.params[9]);
encryMode := ORD(event.params[10]);
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventConnectionComplete: status = 0x"); KernelLog.Hex(status,-2);
KernelLog.String("; handle = "); KernelLog.Int(handle,0); KernelLog.String("; bdAddr = ");
FOR i:= 0 TO Bluetooth.BDAddrLen-1 DO
KernelLog.Hex(ORD(bdAddr[i]),-2);
END;
KernelLog.String("; linkType = "); KernelLog.Int(linkType,0);
KernelLog.String("; encryptionMode = "); KernelLog.Int(encryMode,0);
KernelLog.Ln;
END;
IF (OnConnectionComplete # NIL) THEN
OnConnectionComplete(SELF,status,handle,bdAddr,linkType,encryMode);
END;
END EventConnectionComplete;
PROCEDURE EventDisconnectionComplete(event: Bluetooth.EventPacket);
VAR
status,handle,reason : LONGINT;
BEGIN
status := ORD(event.params[0]);
handle := (ORD(event.params[2])*100H + ORD(event.params[1])) MOD 1000H;
reason := ORD(event.params[3]);
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventDisconnectionComplete: status = 0x"); KernelLog.Hex(status,-2);
KernelLog.String("; handle = "); KernelLog.Int(handle,0);
KernelLog.String("; reason = 0x"); KernelLog.Hex(reason,-2);
KernelLog.Ln;
END;
IF (OnDisconnectionComplete # NIL) THEN
OnDisconnectionComplete(SELF,status,handle,reason);
END;
END EventDisconnectionComplete;
PROCEDURE EventConnectionCompleteOLD(event: Bluetooth.EventPacket);
VAR
status,handle,i : LONGINT;
bdAddr : Bluetooth.BDAddr;
link : Link;
BEGIN
status := ORD(event.params[0]);
IF (status = 0) THEN
handle := (ORD(event.params[2])*100H + ORD(event.params[1])) MOD 1000H;
FOR i := 0 TO Bluetooth.BDAddrLen-1 DO
bdAddr[i] := event.params[3+i]
END;
link := linkManager.FindLink(handle);
IF (link = NIL) THEN
NEW(link,SELF, bdAddr,handle);
linkManager.AddLink(link);
END;
link.state := lsUp;
link.type := ORD(event.params[9]);
link.encryption := ORD(event.params[10]);
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventConnectionCompleteOLD: status = 0x"); KernelLog.Hex(status,-2);
KernelLog.String("; handle = "); KernelLog.Int(link.handle,0); KernelLog.String("; bdAddr = ");
FOR i:= 0 TO Bluetooth.BDAddrLen-1 DO
KernelLog.Hex(ORD(bdAddr[i]),-2);
END;
KernelLog.String("; linkType = "); KernelLog.Int(link.type,0);
KernelLog.String("; encryptionMode = "); KernelLog.Int(link.encryption,0);
KernelLog.Ln;
END;
ELSE
handle := -1; link := NIL;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventConnectionCompleteOLD: status = 0x"); KernelLog.Hex(status,-2);KernelLog.Ln;
END;
END;
IF (OnConnect # NIL) THEN
OnConnect(SELF,link,status)
END;
END EventConnectionCompleteOLD;
PROCEDURE EventDisconnectionCompleteOLD(event: Bluetooth.EventPacket);
VAR
status,handle : LONGINT;
link : Link;
BEGIN
status := ORD(event.params[0]);
IF (status = 0) THEN
handle := (ORD(event.params[2])*100H + ORD(event.params[1])) MOD 1000H;
link := linkManager.FindLink(handle);
IF (link # NIL) THEN
link.state := lsDown;
link.reason := ORD(event.params[3]);
linkManager.RemoveLink(link);
END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventDisconnectionCompleteOLD: status = 0x"); KernelLog.Hex(status,-2);
KernelLog.String("; handle = "); KernelLog.Int(handle,0);
KernelLog.String("; reason = 0x"); KernelLog.Hex(link.reason,-2);
KernelLog.Ln;
END;
ELSE
link := NIL;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.EventDisconnectionCompleteOLD: status = 0x"); KernelLog.Hex(status,-2);KernelLog.Ln;
END;
END;
IF (OnDisconnect # NIL) THEN
OnDisconnect(SELF,link,status)
END;
END EventDisconnectionCompleteOLD;
PROCEDURE EventNumOfCompletedPackets(event: Bluetooth.EventPacket);
VAR
numOfHandles,handle,numOfCompletedPackets : LONGINT;
link : Link;
ofs,i : LONGINT;
BEGIN
i := 0; numOfHandles := ORD(event.params[0]);
WHILE (i < numOfHandles) DO
ofs := 1 + i*4;
handle := (ORD(event.params[ofs])+LONG(ORD(event.params[ofs+1]))*100H) MOD 1000H;
numOfCompletedPackets := ORD(event.params[ofs+2])+LONG(ORD(event.params[ofs+3]))*100H;
link := linkManager.FindLink(handle);
IF (link # NIL) THEN
INC(link.nofPackets, numOfCompletedPackets);
END;
INC(i);
END;
END EventNumOfCompletedPackets;
PROCEDURE EventMaxSlotsChange(event: Bluetooth.EventPacket);
VAR
handle,maxSlots : LONGINT;
BEGIN
handle := (ORD(event.params[1])*100H + ORD(event.params[0])) MOD 1000H;
maxSlots := ORD(event.params[2]);
KernelLog.String(ModuleName);
KernelLog.String("EventMaxSlotsChange: handle = "); KernelLog.Int(handle,0);
KernelLog.String(" max slots = "); KernelLog.Int(maxSlots,0);
KernelLog.Ln
END EventMaxSlotsChange;
PROCEDURE EventPageScanRepModeChange(event: Bluetooth.EventPacket);
VAR
i : LONGINT;
BEGIN
KernelLog.String(ModuleName);
KernelLog.String("EventPageScanRepititionModeChange: bdAddr = ");
FOR i := 0 TO Bluetooth.BDAddrLen-1 DO
KernelLog.Hex(ORD(event.params[i]),-2);
END;
KernelLog.String(" mode = R"); KernelLog.Int(ORD(event.params[Bluetooth.BDAddrLen]),0);
KernelLog.Ln
END EventPageScanRepModeChange;
PROCEDURE EricssonFilter(packet: Bluetooth.Packet): BOOLEAN;
BEGIN RETURN packet(Bluetooth.EventPacket).code = 0FFX
END EricssonFilter;
PROCEDURE EricssonHandler(packet: Bluetooth.Packet);
VAR event: Bluetooth.EventPacket; i: LONGINT;
BEGIN
event := packet(Bluetooth.EventPacket);
KernelLog.Enter;
CASE event.params[0] OF
| 01X: KernelLog.String("Ericsson OSE crash")
| 04X: KernelLog.String("Ericsson OSE pool event")
| 06X: KernelLog.String("Message from Ericsson module on TL '"); KernelLog.String(tl.name); KernelLog.String("': ");
FOR i := 0 TO ORD(event.params[1])-1 DO KernelLog.Char(event.params[2+i]) END;
ELSE KernelLog.String("unknown Ericsson event")
END;
KernelLog.Exit
END EricssonHandler;
PROCEDURE ACLFilter(packet: Bluetooth.Packet): BOOLEAN;
BEGIN RETURN TRUE
END ACLFilter;
PROCEDURE ACLHandler(packet: Bluetooth.Packet);
VAR acl: Bluetooth.ACLPacket; l: Link;
BEGIN
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.ACLHandler: ..."); KernelLog.Ln;
END;
acl := packet(Bluetooth.ACLPacket);
l := linkManager.FindLink(acl.handle);
IF (l # NIL) THEN l.ACLDataReceived(acl) END;
IF TraceHCI THEN
KernelLog.String(ModuleName);
KernelLog.String("HCI.ACLHandler: done."); KernelLog.Ln;
END;
END ACLHandler;
PROCEDURE ErrorFilter(packet: Bluetooth.Packet): BOOLEAN;
BEGIN RETURN (packet IS Bluetooth.UnknownPacket)
END ErrorFilter;
PROCEDURE ErrorHandler(packet: Bluetooth.Packet);
BEGIN
IF (OnError # NIL) THEN
OnError(packet)
END
END ErrorHandler;
END HCI;
ConnectionComplete* = PROCEDURE {DELEGATE} (sender: HCI; status, handle: LONGINT;
bdAddr: Bluetooth.BDAddr; linkType, encryMode: LONGINT);
DisconnectionComplete* = PROCEDURE {DELEGATE} (sender : HCI; status,handle,reason : LONGINT);
InquiryComplete* = PROCEDURE {DELEGATE} (sender: HCI; status: LONGINT);
ConnectionEvent* = PROCEDURE{DELEGATE} (sender: HCI; link: Link; res: LONGINT);
InquiryEvent* = PROCEDURE {DELEGATE} (sender: HCI; bdAddr: Bluetooth.BDAddr; deviceClass: Bluetooth.DeviceClass;
psRepMode, psPeriodMode, psMode, clockOffset: LONGINT);
GeneralEvent* = PROCEDURE {DELEGATE} (sender: HCI; event: Bluetooth.EventPacket);
ErrorEvent* = PROCEDURE{DELEGATE} (packet: Bluetooth.Packet);
PROCEDURE ComposeCommandHeader*(OGF, OCF, paramLen: LONGINT; VAR command: ARRAY OF CHAR);
BEGIN
ASSERT((0 <= OGF) & (OGF <= 03FH));
ASSERT((0 <= OCF) & (OCF <= 03FFH));
ASSERT((0 <= paramLen) & (paramLen <= 0FFH));
command[0] := CHR(OCF MOD 100H);
command[1] := CHR(OCF DIV 100H + OGF*4);
command[2] := CHR(paramLen)
END ComposeCommandHeader;
END BluetoothHCI.