;Host Controller Interface (HCI) routines include "settings.inc" include "ti83plus.inc" include "equates.inc" include "usb8x.inc" include "bluetooth.inc" SEGMENT Main GLOBALS ON EXTERN IPutC,DispHexA,cmpstrb HCI_CreateConnection: ;Establishes a connection to a remote Bluetooth device. ;Inputs: IX points to an inquiry result structure ; DE is the packet type ; HL points to a 10-byte buffer for a connection handle ;Outputs: Connection handle buffer filled ; Carry flag set if problems ld (ptrData),hl ld hl,OP1 ld b,6 $$: ld a,(ix+0) ld (hl),a inc hl inc ix djnz $B ld (hl),e inc hl ld (hl),d inc hl ld a,(ix+0) ld (hl),a inc hl ld (hl),0 inc hl ld a,(ix+5) ld (hl),a inc hl ld a,(ix+6) or 80h ld (hl),a inc hl ld (hl),0 ;do not allow role switch ld hl,OP1 ld de,ogfLinkControl*256+hciCreateConnection ld bc,13 ld ix,eventDataBuffer call SendHCICommand ret c ld hl,eventDataBuffer call RequestHCIData ret c ld a,(eventDataBuffer) cp Event_ConnectionComplete scf ret nz ld a,(eventDataBuffer+2) or a scf ret nz ;Fill in the connection handle ld hl,eventDataBuffer+3 ld de,(ptrData) ld bc,10 ldir ;Request more data so we can handle device events ld ix,responseFlag set deviceConnected,(ix+0) ld hl,eventDataBuffer call RequestHCIData_NoWait xor a ret HCI_Disconnect: ;Disconnects from a remote Bluetooth device. ;Inputs: IX points to a connection handle structure ; B is disconnection reason (0 for default) ;Outputs: Device is disconnected ; Carry flag set if problems ld hl,OP1 ld a,(ix+0) ld (hl),a inc hl ld a,(ix+1) ld (hl),a inc hl ld a,b or a jr nz,$F ld a,0Fh $$: ld (hl),a dec hl dec hl ld de,ogfLinkControl*256+hciDisconnect ld bc,3 ld ix,eventDataBuffer call SendHCICommand ret c ld hl,eventDataBuffer call RequestHCIData ret c ld a,(eventDataBuffer) cp Event_DisconnectionComplete scf ret nz ld a,(eventDataBuffer+2) or a scf ret nz ld ix,responseFlag res deviceConnected,(ix+0) xor a ret SendHCICommand: ;Sends an HCI command and requests a response. ;Inputs: HL points to the parameter data (must reside in RAM) ; B is flags byte (reserved for future use, pass 0 for defaults) ; C is the size of the parameter data (or 0 for no data) ; D is the OGF (ogfLinkControl = Link Control command; ; ogfHCIPolicy = HCI Polcy command; ; ogfHCBaseband = Host Controller and Baseband command) ; E is the OCF (command to execute) ; IX points to buffer for received data (if applicable for the given command) (must reside in RAM) ;Outputs: Data written to buffer ; Carry flag set if error ; A contains error code (or 0 for no error) ;Destroys: All registers ; OP1 ld (ptrInputBuffer),ix ld ix,eventDataBuffer ld (ix+0),e ld (ix+1),d ld (ix+2),c ld de,eventDataBuffer+3 ld b,0 ld a,c or a jr z,$F ldir $$: ld hl,eventDataBuffer ex de,hl or a sbc hl,de push hl ld hl,sDeviceRequest ld de,OP1 ld bc,8 ldir pop bc ld a,c ld (OP1+6),a ld hl,OP1 ld de,eventDataBuffer ld b,c U_CALL SendControlDataOut ld a,errHCICommandFailedSend ret c ld hl,(ptrInputBuffer) RequestHCIData: ;Requests HCI data (for now just HCI events) ;Inputs: ; HL is buffer to store data to ;Outputs: ; Data placed in buffer ; Returns carry flag set if problems call RequestHCIData_NoWait ld ix,responseFlag HCIResponseLoop: ei halt in a,(4) bit 3,a scf ld a,errOnAborted ret z bit cmdComplete,(ix+0) jr z,HCIResponseLoop xor a ret RequestHCIData_NoWait: ;Requests HCI data (for now just HCI events) ;Inputs: ; HL is buffer to store data to ;Outputs: ; Receive request made ld (ptrInputBuffer),hl ld ix,responseFlag res cmdStarted,(ix+0) res cmdComplete,(ix+0) ld a,(interruptPipe) ld b,a U_CALL ReqData ret sDeviceRequest: DB 20h,00h,00h,00h,00h,00h,03h,00h HCI_DoInquiryScan: ;Performs an inquiry scan for nearby Bluetooth devices. ;The scan will last for ~30 seconds and then return with results. ;Inputs: HL points to buffer for inquiry results ; B is the time to wait in 1.28-second units, up to 60 seconds (01h to 30h) (or 0 for default (30 seconds)). ;Outputs: Buffer is filled with array of 14-byte inquiry result "objects": ; Bytes Name ; 6 BD_ADDR (unique address of device) ; 1 Page_Scan_Repetition_Mode ; 1 Reserved1 ; 1 Reserved2 ; 3 Class_of_Device ; 2 Clock_Offset ; B contains the number of results. ; Carry flag set if problems ; A contains error code (or 0 if no error) ;Destroys: ; All registers ; appData ld a,b push hl ld hl,startInquiry ld de,OP1 ld bc,startInquiryEnd-startInquiry ldir or a jr z,$F ld (OP1+3),a $$: ld hl,OP1 ld de,ogfLinkControl*256+hciInquiry ld bc,startInquiryEnd-startInquiry ld ix,eventDataBuffer call SendHCICommand pop hl ret c ld (appData+1),hl ld (ptrData),hl xor a ld (appData),a inquiryLoop: ld a,(eventDataBuffer) cp Event_InquiryComplete jr z,inquiryDone cp Event_CommandComplete jr z,inquiryDone cp Event_InquiryResult jr nz,inquiryContinue ;We have an inquiry result event, let's parse it out ld b,0 inquiryParseLoop: ;Do we already have this BD_ADDR? If so, ignore it. push bc call DoesBD_ADDRExist pop bc jr nc,inquiryParseSkip ld de,(appData+1) ;Get the BD_ADDR ld c,6 ld l,0 call StoreParameterValue ;Get Page_Scan_Repetition_Mode ld c,1 ld l,6 call StoreParameterValue ;Get Reserved1 ld c,1 ld l,7 call StoreParameterValue ;Get Reserved2 ld c,1 ld l,8 call StoreParameterValue ;Get Class_of_Device ld c,3 ld l,9 call StoreParameterValue ;Get Clock_Offset ld c,2 ld l,12 call StoreParameterValue ld (appData+1),de ;update the buffer pointer ld a,(appData) ;update the count of results inc a ld (appData),a inquiryParseSkip: inc b ld a,(eventDataBuffer+2) ;gone through all of the results yet? cp b jr nz,inquiryParseLoop inquiryContinue: ld hl,eventDataBuffer call RequestHCIData ret c jr inquiryLoop inquiryDone: ld a,(appData) ld b,a xor a ret DoesBD_ADDRExist: ;Checks to see if index B's BD_ADDR is already in our device list ld a,(appData) or a scf ret z ;nothing in our list, so obviously not ld c,a ld de,(ptrData) dbdExistLoop: push bc ld l,0 ld c,6 call GetParameterValue ld b,6 call cmpstrb pop bc ret z ld hl,14 add hl,de ex de,hl dec c jr nz,dbdExistLoop scf ret StoreParameterValue: ;B = index we want ;C = size of item we want ;L = sum of all arrays before the item we want ;DE points to buffer call GetParameterValue push bc ld b,0 ldir pop bc ret GetParameterValue: ;n*(sum of size of all arrays before the one you want)+(i*s), where n is the number of total items, i is the index you want, and s is the size of the array item you want ;B = index we want (result 0, result 1, result 2, etc.) ;C = size of the item we want (6 for BD_ADDR, 1 for Page_Scan_Repetition_Mode, 1 for Reserved1, etc.) ;L = sum of size of all arrays before the item we want (0 for BD_ADDR, 6 for Page_Scan_Repetition_Mode, 7 for Reserved1, etc.) push bc push de ;Get the first offset ld a,l or a jr nz,$F ld hl,0 jr gpvContinue $$: ld a,(eventDataBuffer+2) ld h,a call HTimesL gpvContinue: ;HL is the first offset ;Now we need B*C ex de,hl push bc pop hl ld a,h or a jr nz,$F ld hl,0 jr gpvContinue2 $$: call HTimesL gpvContinue2: ;DE is the first offset ;HL is the second offset push de pop bc ;BC is the first offset ;HL is the second offset add hl,bc ;HL is the offset into the buffer ld de,eventDataBuffer+3 add hl,de ;HL points to the data we want pop de pop bc ret HTimesL: push bc push de B_CALL HTimesL pop de pop bc ret startInquiry: DB 33h,8Bh,9Eh DB 18h DB 00h ;number of responses (unlimited) startInquiryEnd: HCI_RequestRemoteName: ;Requests the user-friendly name of a remote Bluetooth device. ;Inputs: ; IX points to an inquiry result structure ; HL points to 249-byte buffer for friendly name ;Outputs: ; Friendly name written to buffer, zero-terminated ; Returns carry flag set if problems ld (ptrData),hl ld hl,OP1 ld b,7 $$: ld a,(ix+0) ld (hl),a ;BD_ADDR + Page_Scan_Repetition_Mode inc hl inc ix djnz $B ld (hl),0 ;Reserved inc hl ld a,(ix+5) ld (hl),a ;Clock_Offset 1 inc hl ld a,(ix+6) or 80h ld (hl),a ;Clock Offset 2 ld de,ogfLinkControl*256+hciRemoteNameRequest ld bc,10 ld ix,eventDataBuffer ld hl,OP1 call SendHCICommand ret c $$: ld hl,eventDataBuffer call RequestHCIData ret c ld a,(eventDataBuffer) cp Event_RemoteNameRequestComplete jr nz,$B ld de,(ptrData) ld hl,eventDataBuffer+9 ld bc,248 ldir xor a ld (de),a ret HCI_SetLocalDeviceName: ;Sets the user-friendly name of the local Bluetooth device. ;Inputs: ; HL points to zero-terminated name (249-byte maximum) ;Outputs: ; Friendly name written to device ; Returns carry flag set if problems ld de,ogfHCBaseband*256+hciWriteLocalName ld bc,248 ld ix,eventDataBuffer call SendHCICommand ret c ld a,(eventDataBuffer) cp Event_CommandComplete scf ret nz ld a,(eventDataBuffer+5) or a scf ret nz xor a ret HCI_GetLocalDeviceName: ;Gets the user-friendly name of the local Bluetooth device. ;Inputs: ; HL points to 249-byte maximum buffer to store the name ;Outputs: ; Friendly name written to buffer (zero-terminated) ; Returns carry flag set if problems ld (hl),0 push hl ld de,ogfHCBaseband*256+hciReadLocalName ld bc,0 ld ix,eventDataBuffer call SendHCICommand pop de ret c ld hl,eventDataBuffer+6 ld bc,248 ldir xor a ld (de),a ret HCI_SetScanMode: ;Sets the scan mode of the local Bluetooth device. This is what enables and disables inquiry scans and discovery mode. ;Inputs: ; A is the scan mode: ; 00h: inquiry scans and page scans ("discoverable" mode) is disabled. ; 01h: inquiry scans are enabled, but page scans ("discoverable" mode) is disabled. This is the default. ; In this mode, the device can do inquiry scans to find other devices, but is not discoverable. ; 02h: inquiry scans are disabled, but page scans ("discoverable" mode) is enabled. I've yet to see this work. ; 03h: both inquiry scans and page scans ("discoverable" mode) are enabled. ; In this mode, the device can do inquiry scans to find other devices, and is also discoverable by other devices. ;Outputs: ; Scan mode set ; Returns carry flag set if problems ld hl,OP1 ld (hl),a ld de,ogfHCBaseband*256+hciWriteScanEnable ld bc,1 ld ix,eventDataBuffer call SendHCICommand ret c ld a,(eventDataBuffer) cp Event_CommandComplete scf ret nz ld a,(eventDataBuffer+5) or a scf ret nz xor a ret HCI_SetDeviceClass: ;Sets the class of device for the local Bluetooth device. ;Inputs: ; HL points to the Class_of_Device parameter as it would be sent over the air: ;Outputs: ; Device class set ; Returns carry flag set if problems ld de,ogfHCBaseband*256+hciWriteClassOfDevice ld bc,3 ld ix,eventDataBuffer call SendHCICommand ret c ld a,(eventDataBuffer) cp Event_CommandComplete scf ret nz ld a,(eventDataBuffer+5) or a scf ret nz xor a ret