Os projetistas do Bluetooth gostam de "empilhar" protocolos: RFCOMM sobre L2CAP sobre ACL sobre HCI sobre o rádio Bluetooth que é complicado pra c@$#*.
E o empilhamento prossegue acima do L2CAP e do RFCOMM também. O Bluetooth usa o conceito de "profile", ou perfil, para implementar determinado serviço.
A rigor, não é necessário haver um perfil para haver comunicação. No código em Python do artigo anterior, ninguém falou de perfil; especificamos a porta RFCOMM 10 e pronto. Mas também ficou por nossa conta definir qual o protocolo de aplicação, e para que ele vai servir. A existência dos perfis facilita a interoperabilidade.
Por exemplo, o perfil SPP (Serial Port Profile) é extremamente simples. Ele define um serviço que simula um cabo serial, e impõe o uso do RFCOMM como transporte. Nada mais que isso.
Os perfis podem ser "empilhados" também. Por exemplo, o perfil DUN (Dial-Up Networking) é uma especialização do SPP. O serviço DUN especifica que haverá um modem no lado servidor, que serve para discar à Internet.
Como o DUN é empilhado em cima do SPP, as definições do SPP continuam valendo para o DUN: é um serviço semelhante a cabo serial, em cima de RFCOMM.
O perfil OPUSH implementa um serviço para troca de objetos (normalmente, mensagens e arquivos), utilizando o protocolo OBEX sobre transporte RFCOMM.
Existem inúmeros perfis, para impressoras, fax, mouse, teclado, emulação de LAN. Há diversos perfis "proprietários", dedicados a apenas um tipo de dispositivo, ou a um fabricante (exemplos: NGAGE, PCSUITE, WIIMOTE).
Uma parte importante do perfil, é que ele especifica como os outros dispositivos em volta vão "achar" o serviço. Para isto, dependemos do protocolo SDP.
O SDP faz papel análogo ao Bonjour do Mac OS X. Ele viabiliza a descoberta de serviços nos dispositivos próximos, bem como suas portas RFCOMM, PSMs L2CAP, e nomes descritivos dos serviços. (Os nomes dos dispositivos são obtidos de outra forma, portanto o SDP não é análogo ao DNS.)
Todo dispositivo BT que não esteja oculto deve implementar o SDP, que sempre atende na mesma porta (L2CAP, PSM 1). O protocolo SDP é no estilo TLV (type, length, value), e pode conter diversos tipos de dados, bem como seqüências. Por ser tão genérico, o SDP permite a difusão de praticamente qualquer tipo de dado.
Aqui entra a importância dos perfis; são eles que ditam o formato dos dados difundidos via SDP. Cada perfil especifica um formato de "ficha de serviço" (service record). Nesta ficha, podem ser encontrados os dados essenciais à conexão (porta, PSM). A padronização garante que o lado cliente, interessado em determinado perfil, será capaz de interpretar a ficha de serviço sem problemas.
Quando um aplicativo deseja prestar um determinado serviço, ele deve criar a ficha no formato ditado pelo perfil, e solicitar a publicação da ficha via SDP. Idealmente, se houver um outro dispositivo próximo interessado em conectar àquele serviço, ele descobrirá os dispositivos à sua volta, obterá as fichas de serviço via SDP, descobrirá o serviço recém-publicado e fará conexão.
Se quiséssemos que aquele "servidor" em Python do artigo anterior aparecesse no SDP, a forma mais simples de conseguir isto é usando o sdptool. Não muito profissional, mas funciona.
epx@neosaldina:~$ sdptool add --channel=10 SP Serial Port service registered epx@neosaldina:~$ sdptool browse local Browsing FF:FF:FF:00:00:00 ... ... Service Name: Serial Port Service Description: COM Port Service Provider: BlueZ Service RecHandle: 0x10008 Service Class ID List: "Serial Port" (0x1101) Protocol Descriptor List: "L2CAP" (0x0100) "RFCOMM" (0x0003) Channel: 10 Language Base Attr List: code_ISO639: 0x656e encoding: 0x6a base_offset: 0x100 Profile Descriptor List: "Serial Port" (0x1101) Version: 0x0100
A ficha acima é exibida num formato bastante mastigado e legível. Internamente, cada item corresponde a um bytecode e a ficha toda ocupa uns poucos bytes. Note que no "Protocol Descriptor List", menciona-se L2CAP e RFCOMM, mas apenas o RFCOMM possui uma porta mencionada (10).
Para termos mais controle sobre o conteúdo da ficha, teríamos de usar uma API "séria" para criá-la e publicá-la. No caso do BlueZ, a API recomendada é a via D-BUS, e a ficha é especificada num formato XML. (Também existe uma API C, mas seu uso é desaconselhado.)