Bluetooth Serial Port Protocol (SPP)
With webOS 2.0, your app can use the Bluetooth SPP to access certain Bluetooth devices. At this time, only the SPP is exposed. Note that you can see what Bluetooth profiles your device supports in the Device Info application.
Bluetooth Code Sample - GPS Device
The SDK code samples contain a Bluetooth project which opens a port to a Bluetooth GPS device and reads its position data.
In this section:
Methods
-
GAP method -- URI is
com.palm.bluetooth/gap -
SPP Access Methods -- URI is
com.palm.bluetooth/spp -
SPP Data Transfer Methods -- URI is
com.palm.service.bluetooth.spp
Basic Process for Server/Client Data Exchange
Before beginning, both client and server webOS devices should have "paired" using their Bluetooth installed programs. Bluetooth pairing happens when two Bluetooth enabled devices agree to communicate with one another. Both devices have to have Bluetooth turned on so they can "discover" one another. When they agree to communicate, the two devices join what is called a "trusted pair."
Server
- Call subscribenotifications to receive SPP notifications.
- Call enableserver to make device an SPP server with specified service name.
- Wait for connect notification from client device. Extract instance ID.
- Using instance ID from client, open an SPP port for client communications.
- Write data to client. Repeat calling write until done.
- Wait until disconnect notification arrives from client before calling close to remove the port connection.
- Call disableserver to remove device as SPP server.
Client
- Call subscribenotifications to receive SPP notifications.
- Call gettrusteddevices to get a list of paired devices from the Bluetooth service.
- Call connect to connect to server device.
- Wait for service names notification to arrive. Extract service's instance ID and service name.
- Call selectservice using service name and instance ID from service names notification.
- Use instance ID to open port to Server.
- Read data from server. Repeat calling read until done.
- Close port to server.
- Disconnect from server.
Notifications
When an app calls subscribenotifications, they can begin receiving one of the following SPP notifications.
Syntax
{
"notification" : string,
"instanceId" : int,
"address" : string,
"name" : string,
"services" : string array,
"error" : int
}
Parameters
| Parameter | Required | Type | Description |
| notification | Yes | string |
One of the following:
|
| instanceId | No | int | Subscribed service identifier. Sent for notifnservicenames, notifnconnected, and notifndisconnected. |
| address | No | string |
Bluetooth device address containing hex digits for an IEEE standard MAC address, i.e., "00:0d:b5:38:c0:3f". Sent for notifnconnected and notifndisconnected.
|
| name | No | string | User given device name, i.e., "Joe's HP TouchPad". Sent for notifnconnected and notifndisconnected. |
| services | No | string array | Array of SPP server names. Sent for notifnservicenames. |
| error | No | int | Error code. 0 = No error. |
Examples
{
"notification":"notifnserverenabled",
"error":0
}
{
"notification":"notifnservicenames",
"instanceId":23,
"services":[
"HPQA"
]
}
{
"notification":"notifnconnected",
"address":"00:1d:fe:77:c3:a7",
"name":"Joe's HP TouchPad",
"instanceId":27,
"error":0
}
{
"notification":"notifndisconnected",
"address":"08:1d:fe:77:c2:d3",
"name":"My Palm3",
"instanceId":23,
"error":0
}
Mojo -- Sample Notification Implementation Code
Note that this is not a completely self-contained example, but should give you some idea of flow. Note also that this is server side code, the code for a client would be somewhat different.
MainAssistant.prototype.setup = function()
{
this.count = 0;
this.maxcount = 10;
this.urlgap = 'palm://com.palm.bluetooth/gap';
this.urlspp = 'palm://com.palm.bluetooth/spp';
this.urlservice = 'palm://com.palm.service.bluetooth.spp';
}
MainAssistant.prototype.subscribe = function(sub)
{
var msg =
{
method: "subscribenotifications",
parameters: {"subscribe": true},
onSuccess: this.sppNotify.bind(this),
};
this.sppNotificationService = this.serviceRequest(this.urlspp, msg);
}
MainAssistant.prototype.sppNotify = function(objData)
{
var that = this; // for scoping
if (! objData.notification)
{
this.log("sppNotify", Object.toJSON(objData));
if (objData.returnValue && objData.subscribed)
{
this.enableserver(true);
}
return;
}
switch(objData.notification)
{
case "notifnserverenabled":
this.log(objData.notification, "error = " + objData.error);
break;
case "notifnserverdisabled":
this.log(objData.notification, "error = " + objData.error);
if (this.count >= this.maxcount)
{
this.log("", "SUCCESSFUL!");
}
break;
case "notifnconnected":
this.log(objData.notification, objData.instanceId);
if (objData.error === 0)
{
this.open(objData.instanceId);
}
break;
case "notifndisconnected":
this.log(objData.notification, "Connection terminated/Out of range");
this.enableserver(false);
break;
default:
this.log(objData.notification, Object.toJSON(objData));
break;
}
}
GAP Method
GAP (Generic Access Profile) defines how two Bluetooth units discover and establish a connection with each other.
The URI for the one GAP method is:
com.palm.bluetooth/gap/gettrusteddevices
gettrusteddevices
Return information about Bluetooth devices that are paired with a webOS device.
Syntax
{}
Parameters
None.
Returns
{
"returnValue" : boolean,
"trusteddevices" :
[{
"address" : string,
"name" : string,
"cod" : int,
"renamed" : boolean,
"status" : string,
"mapstate" : int,
"pbapstate" : int,
"hfstate" : int,
"autoconnectstate" : int
}]
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| trusteddevices | Yes | object array | Array of objects. See fields below. If no trusted devices, this is an empty array. |
| address | No | string |
Bluetooth device address containing hex digits for an IEEE standard MAC address, i.e., "00:0d:b5:38:c0:3f".
|
| name | No | string |
Device name, e.g., "BT-GPS-38C03F"
|
| cod | No | int | Class of device -- indicates the device type and which types of services it supports. |
| renamed | No | boolean | Indicates if user has modified device's name. |
| status | No | string | connected|disconnected |
| mapstate | No | int | Message Access (SMS) state - 1 (yes), 2 (no), or 255 (undefined). Indicates if the user has set the "Receive SMS" option to "ON". |
| pbapstate | No | int | Phone Book Access state - 1 (yes), 2 (no), or 255 (undefined). Indicates if the user has set the "Receive Phone Calls" option to "ON". |
| hfstate | No | int | Hands Free state, only for webOS tablet acting as headset - 1 (yes), 2 (no), or 255 (undefined). |
| autoconnectstate | No | int | Only for webOS devices -- paired devices can receive the same phone calls or sms notifications if both have "Receive Phone Calls" (pbap), "Receive SMS" (map) and "Auto-Connect" all set to "ON". Note that these options are available when you select a paired device in the Bluetooth app. These devices will automatically connect when they come into each other's range. 1 (yes), 2 (no), or 255 (undefined). |
Examples
Enyo
...
{
name : "getDevices",
kind : "PalmService",
service : "palm://com.palm.bluetooth/gap/",
method : "gettrusteddevices",
onSuccess : "getDevicesFinished",
onFailure : "getDevicesFail",
onResponse : "gotResponse",
subscribe : true
}
...
getDevicesFinished : function(inSender, inResponse) {
enyo.log("gettrusteddevices success, results=" + enyo.json.stringify(inResponse));
},
getDevicesFail : function(inSender, inResponse) {
enyo.log("gettrusteddevices failure, results=" + enyo.json.stringify(inResponse));
},
getDevicesCall : function(inSender, inResponse)
{
this.$.getDevices.call({});
}
Mojo
this.controller.serviceRequest('palm://com.palm.bluetooth/gap', {
method: 'gettrusteddevices',
parameters: {},
onSuccess : function (e){ Mojo.Log.info("gettrusteddevices success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("gettrusteddevices failure, results="+JSON.stringify(e)); }
});
Success
gettrusteddevices success, results=
{
"returnValue":true,
"trusteddevices":[
{
"address":"70:1a:04:9c:20:9a",
"name":"E64004CRBVL1",
"cod":4063500,
"renamed":true,
"status":"disconnected",
"mapstate":1,
"pbapstate":255,
"hfstate":1,
"autoconnectstate":1
}
]
}
SPP Access Methods
SPP (Serial Port Profile) is based on ETSI 07,10 and the RFCOMM protocol. It emulates a serial cable to provide a simple substitute for existing RS-232, including the familiar control signals.
The URI for SPP access is:
com.palm.bluetooth/spp
Methods
- connect -- Connect to an SPP server.
- disableserver -- Disable an SPP server.
- disconnect -- Disconnect from an SPP peer.
- enableserver -- Make device a SPP server with specified service name.
- selectservice -- Select a service from list of services received through notification.
- subscribenotifications -- Subscribe to SPP notifications.
connect
Connect to an SPP server.
Syntax
{
"address" : string
}
Parameters
| Parameter | Required | Type | Description |
| address | Yes | string |
Bluetooth device address containing hex digits for an IEEE standard MAC address, i.e., "00:0d:b5:38:c0:3f".
|
Returns
{
"returnValue" : boolean,
"errorCode" : string,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorCode | No | string | Error code returned on failure. |
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.bluetooth/spp/', {
method: 'connect',
parameters: {
"address" : "00:1d:fe:77:x3:a7"
},
onSuccess : function (e){ Mojo.Log.info("connect success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("connect failure, results="+JSON.stringify(e)); }
});
disableserver
Disable an SPP server.
Syntax
{
"servicename" : string
}
Parameters
| Parameter | Required | Type | Description |
| servicename | Yes | string | Server name. Name used when enabling server. |
Returns
{
"returnValue" : boolean,
"errorCode" : string,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorCode | No | string | Error code returned on failure. |
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.bluetooth/spp/', {
method: 'disableserver',
parameters: {
"servicename":"HPQA"
},
onSuccess : function (e){ Mojo.Log.info("disableserver success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("disableserver failure, results="+JSON.stringify(e)); }
});
disconnect
Disconnect from an SPP peer.
Syntax
{
"address" : string
}
Parameters
| Parameter | Required | Type | Description |
| address | Yes | string |
Bluetooth device address containing hex digits for an IEEE standard MAC address, i.e., "00:0d:b5:38:c0:3f".
|
Returns
{
"returnValue" : boolean,
"errorCode" : string,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorCode | No | string | Error code returned on failure. |
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.bluetooth/spp/', {
method: 'disconnect',
parameters: {
"address":"70:1a:04:9c:20:9a"
},
onSuccess : function (e){ Mojo.Log.info("disconnect success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("disconnect failure, results="+JSON.stringify(e)); }
});
enableserver
Make webOS device an SPP server with a specified service name.
Syntax
{
"servicename" : string
}
Parameters
| Parameter | Required | Type | Description |
| servicename | Yes | string | Service name, 128 characters maximum. |
Returns
{
"returnValue" : boolean,
"errorCode" : string,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorCode | No | string | Error code returned on failure. |
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.bluetooth/spp/', {
method: 'enableserver',
parameters: {"servicename":"HPQA"},
onSuccess : function (e){ Mojo.Log.info("enableserver success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("enableserver failure, results="+JSON.stringify(e)); }
});
Failure
{
"returnValue":false,
"errorCode":134217729,
"errorText":"BtSppEnableServer: Error enabling server"
}
selectservice
Select a service from list of services received through notification.
Syntax
{
"instanceId" : int,
"servicename" : string
}
Parameters
| Parameter | Required | Type | Description |
| instanceId | Yes | integer | Subscribed service identifier. |
| servicename | Yes | string |
Service name, returned from subscribenotifications.
|
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.bluetooth/spp/', {
method: 'selectservice',
parameters: {
"instanceId" : 23,
"servicename":"HPQA"
},
onSuccess : function (e){ Mojo.Log.info("selectservice success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("selectservice failure, results="+JSON.stringify(e)); }
});
Returns
{
"returnValue" : boolean,
"errorCode" : string,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorCode | No | string | Error code returned on failure. |
| errorText | No | string | Error message returned on failure. |
subscribenotifications
Subscribe to SPP notifications.
Syntax
{
"subscribe" : boolean
}
Parameters
| Parameter | Required | Type | Description |
| subscribe | Yes | boolean | Subscribe to Bluetooth SPP notifications flag. |
Returns
{
"returnValue" : boolean,
"errorCode" : string,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorCode | No | string | Error code returned on failure. |
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.bluetooth/spp/', {
method: 'subscribenotifications',
parameters: { "subscribe": true },
onSuccess : function (e){ Mojo.Log.info("subscribenotifications success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("subscribenotifications failure, results="+JSON.stringify(e)); }
});
Success
{"returnValue":true,"subscribed":true}
SPP Data Transfer Methods
The URI for Serial Port Profile Data Transfer is:
com.palm.service.bluetooth.spp
Methods
- close -- Closes a Bluetooth SPP communication channel.
- open -- Opens a Bluetooth SPP port for communication.
- read -- Reads data from an SPP port.
- write -- Writes data to an SPP port.
close
Close Bluetooth SPP communication channel.
Syntax
{
"instanceId" : int
}
Parameters
| Parameter | Required | Type | Description |
| instanceId | Yes | integer | Subscribed service identifier. |
Returns
{
"returnValue" : boolean,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.service.bluetooth.spp', {
method: 'close',
parameters: { "instanceId" : 23},
onSuccess : function (e){ Mojo.Log.info("close success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("close failure, results="+JSON.stringify(e)); }
});
open
Opens a Bluetooth SPP port for communication.
Syntax
{
"instanceId" : int
}
Parameters
| Parameter | Required | Type | Description |
| instanceId | Yes | integer | Subscribed service identifier. |
Returns
{
"returnValue" : boolean,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.service.bluetooth.spp', {
method: 'open',
parameters: { "instanceId" : 23},
onSuccess : function (e){ Mojo.Log.info("open success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("open failure, results="+JSON.stringify(e)); }
});
read
Reads data from an SPP port.
Syntax
{
"instanceId" : int,
"dataLength" : int
}
Parameters
| Parameter | Required | Type | Description |
| instanceId | Yes | integer | Subscribed service identifier. |
| dataLength | Yes | integer | Size of the buffer to be read. |
Returns
{
"returnValue" : boolean,
"data" : string,
"dataLength" : int,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| data | No | string | Data |
| dataLength | No | int | Length of data |
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.service.bluetooth.spp', {
method: 'read',
parameters: {
"instanceId" : 23,
"datalength" : 128
},
onSuccess : function (e){ Mojo.Log.info("read success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("read failure, results="+JSON.stringify(e)); }
});
write
Writes data to an SPP port.
Syntax
{
"instanceId" : int,
"data" : string,
"dataLength" : int
}
Parameters
| Parameter | Required | Type | Description |
| instanceId | Yes | integer | Subscribed service identifier. |
| data | Yes | string | Data to write. |
| dataLength | Yes | integer | Size of the buffer to be written. |
Returns
{
"returnValue" : boolean,
"errorText" : string
}
| Parameter | Required | Type | Description |
| returnValue | Yes | boolean |
true (success) or false (failure)
|
| errorText | No | string | Error message returned on failure. |
Examples
Mojo
this.controller.serviceRequest('palm://com.palm.service.bluetooth.spp', {
method: 'write',
parameters: {
"instanceId" : 23,
"data" : "lhasdflkasjhdflasjdhfaouweyroasdfasdfasdfasfdaswqguoyuilj,uiiaewfdas",
"datalength" : 128},
onSuccess : function (e){ Mojo.Log.info("write success, results="+JSON.stringify(e)); },
onFailure : function (e){ Mojo.Log.info("write failure, results="+JSON.stringify(e)); }
});