| WRAP Access Server: User's and Developer's Guide | ||
|---|---|---|
| <<< Previous | Next >>> | |
The Bluetooth in the Access Server is controlled via the TCP socket interface called iWRAP. The first iWRAP server is listening on port 10101. In case of Access Server 2293, the second iWRAP server is listening on port 10102 and the third one is listening on port 10103. All commands to a iWRAP server and replies from the server are plain ASCII strings ending in CR+LF ("\r\n"). Commands and replies are not case sensitive.
When connecting to a server you must first wait for the READY. prompt. Do not send any commands prior to this. Some replies are broadcast to all clients of the server. If you see something that you have not requested or that is not intended for your client (identified by the link identifier), simply ignore the reply.
Normally, the iWRAP is protected with a password buffy. The password can be disabled or changed, see the SET command. If the password is enabled, it must be sent first, immediately following the READY. prompt, to the iWRAP server. Otherwise, all commands will fail.
For an example of using the iWRAP, please see asdk/examples/btsend in the SDK directory.
In the following examples, bold lines are commands sent by the client to the iWRAP server and normal lines are replies received from the iWRAP server by the client.
Bluetooth address (bdaddr) is six hex digits separated by a colon. For example, "00:07:80:80:bf:01". With commands requiring Bluetooth address, you can also use Bluetooth friendly name instead.
Bluetooth channels are numbered from 1 to 30. In Access Server, the Serial Port Profile is assigned to channel number two, the Object Push Profile and File Transfer Profile to channel number three and the LAN Access Profile is on channel number four. The other channels are free for user applications.
Link Identifier (link_id) is a number from 0 to 99 used to identify established Bluetooth connections.
Normally, the iWRAP servers are started automatically upon power-up. You can restart the servers manually (for example, to apply the changes made to the iWRAP settings with setup application without rebooting the system). To restart the servers manually, execute the startup script with option restart:
[root@wrap /] /etc/init.d/bluetooth restart |
When the iWRAP servers start up, it uses the settings configured with the setup application. You can put your extra iWRAP commands in the /etc/bluetooth.conf file. The commands in that file are processed as the last task every time iWRAP server is started.
There are two approaches when writing a iWRAP server program (a program accepting incoming calls) for the Access Server, both having different pros and cons:
Forklistener
iWRAP Client
When writing a client program (a program making an outgoing call), you have to use iWRAP.
This is a standard program reading data from standard input and writing output to standard output. See SDK's directory examples/forkserver/ for an example of this kind of program.
Pros:
Easy to write.
Very robust for simple services.
You don't have to know anything about Bluetooth or iWRAP.
Cons:
Your program is started and stopped for every incoming connection.
If there are multiple connections it is not possible to communicate to external program via one socket.
You can't use stdout for debugging, you have to use syslog or a log file.
iWRAP's advanced features are not available: powermodes, MSC, SDP, inquiry, ...
To setup a forklistener see SET command.
iWRAP client is a program communicating with the iWRAP server via control and data sockets. See SDK's directory examples/btserver/ for an example of this kind of program.
Pros:
The cons with forklistener do not apply.
Cons:
More complex than forklistener.
You must have basic knowledge about Bluetooth and iWRAP.
For documentation about iWRAP read this chapter carefully.
This section describes the commands used for Bluetooth service discovery and local SDP record manipulation. The commands and their replies make use of SDP UUID and attribute values, which are listed in the Bluetooth Assigned Numbers documentation. In the commands documented below, the most useful UUID and attribute values can, however, be replaced with keywords listed in Table 6-3. The same keywords are used in the command replies instead of numeric values, if the parameter SET BLUETOOTH READABLE is set to 1.
Table 6-3. Supported Keywords for Replacing SDP UUIDs or Attributes
| Keyword(s) | Value | Hex Value |
|---|---|---|
| SDP | UUID_SDP | 0001 |
| RFCOMM | UUID_RFCOMM | 0003 |
| OBEX | UUID_OBEX | 0008 |
| BNEP | UUID_BNEP | 000F |
| L2CAP | UUID_L2CAP | 0100 |
| PUBLICBROWSEGROUP, BROWSE, ROOT | UUID_PUBLIC_BROWSE_GROUP | 1002 |
| SERIALPORT, SPP | UUID_SERIALPORT | 1101 |
| LANACCESS, LAN | UUID_LANACCESS | 1102 |
| DIALUPNETWORKING, DUN | UUID_DIALUPNETWORKING | 1103 |
| OBEXOBJECTPUSH, OBJP, OPP | UUID_OBEXOBJECTPUSH | 1105 |
| OBEXFILETRANSFER, FTP | UUID_OBEXFILETRANSFER | 1106 |
| PAN-PANU, PANU | UUID_PANU | 1115 |
| PAN-NAP, NAP | UUID_NAP | 1116 |
| PAN-GN, GN | UUID_GN | 1117 |
| PROTOCOLDESCRIPTORLIST, DESCLIST, DESC | ATTR_PROTOCOLDESCRIPTORLIST | 0004 |
| SERVICENAME, NAME | ATTR_SERVICENAME + BASE_LANG_OFFSET | 0000 + 0100 |
| SECURITYDESCRIPTION | ATTR_SECURITYDESCRIPTION | 030A |
| NETACCESSTYPE | ATTR_ NETACCESSTYPE | 030B |
| MAXNETACCESSRATE | ATTR_ MAXNETACCESSRATE | 030C |
Outgoing RFCOMM Call:
READY.
CALL 00:07:80:80:bf:01 1 RFCOMM
CALL 2
RINGING 2
CONNECT 2 RFCOMM 1042
STATUS 2 MSC 8d
<Client opens socket connection to port 1042 and transfers data>
CLOSE 2
NO CARRIER 2 ERROR 000
|
Incoming RFCOMM Call:
READY.
RING 2 00:07:80:80:bf:01 1 RFCOMM 1042
STATUS 2 MSC 8d
<Client opens socket connection to port 1042 and transfers data>
NO CARRIER 2 ERROR 000
|
Some commands may reply with an error code. The human-readable name of the error is displayed as well, if the SET BLUETOOTH READABLE setting has a value of 1. Error code 8 indicates that the iWRAP server is busy executing any number of commands; there can be several client applications using the stack. Just wait a few seconds and try again. Other error codes indicate unexpected, but often only temporary, communication problems.
You can analyze the error from the numeric code. Values bigger than or equal to 900 are iWRAP errors, described in Table 6-5.
Table 6-5. iWRAP Errors
| Code | Textual Form | Reason |
|---|---|---|
| 900 | SERVICE_NOT_FOUND | Tried to CALL a device whose SDP records doesn't include requested service. |
| 901 | ALREADY_CONNECTED | Tried to CALL a device and a service channel that is already connected. |
| 902 | OUT_OF_HANDLES | Tried to CALL but there are too many open connections. |
| 903 | INVALID_ADDRESS_<addr> | Tried to CALL a device with a friendly name that couldn't be found with inquiry. |
| 904 | REJECTED | Incoming call was rejected by the iWRAP server. |
| 905 | BUSY | Tried to issue SDPATTR but another SDP request was in progress. |
| 906 | BUSY | Tried to issue SDPQUERY but another SDP request was in progress. |
| 907 | NOT_CONNECTED | Tried to CLOSE a connection handle that is not active. |
| 908 | BUSY | Tried to issue SDPSEARCH but another SDP request was in progress. |
| 909 | INVALID_ADDRESS | Tried to NAME a device with a friendly name that can't be found with inquiry. |
| 90a | BUSY | Tried to issue NAME but another NAME was in progress. |
Other error codes can be analyzed as follows. For example NO CARRIER ERROR 465: The number 465 is hexadecimal, sum of 0x400 and 0x65, where 0x400 is a mask which means this is an RFCOMM level error and 0x65 (decimal 101) that the RFCOMM error was connection timeout.
The error codes for each mask are listed in the following tables.
Table 6-7. HCI Error Codes
| HCI Error | Code |
|---|---|
| HCI_SUCCESS | 0 |
| HCI_ERR_UNKNOWN_COMMAND | 1 |
| HCI_ERR_NOCONNECTION | 2 |
| HCI_ERR_HARDWARE_FAIL | 3 |
| HCI_ERR_PAGE_TIMEOUT | 4 |
| HCI_ERR_AUTHENTICATION_FAILED | 5 |
| HCI_ERR_KEY_MISSING | 6 |
| HCI_ERR_MEMORY_FULL | 7 |
| HCI_ERR_CONNECTION_TIMEOUT | 8 |
| HCI_ERR_MAX_NUM_CONNECTIONS | 9 |
| HCI_ERR_MAX_NUM_SCO_CONNECTIONS | 10 |
| HCI_ERR_ACL_CONN_ALREADY_EXISTS | 11 |
| HCI_ERR_COMMAND_DISALLOWED | 12 |
| HCI_ERR_HOST_REJECTED_0D | 13 |
| HCI_ERR_HOST_REJECTED_0E | 14 |
| HCI_ERR_HOST_REJECTED_0F | 15 |
| HCI_ERR_HOST_TIMEOUT | 16 |
| HCI_ERR_UNSUPPORTED_PARAM_VALUE | 17 |
| HCI_ERR_INVALID_HCI_PARAMETER_VALUE | 18 |
| HCI_ERR_OTHER_END_TERMINATE_13 | 19 |
| HCI_ERR_OTHER_END_TERMINATE_14 | 20 |
| HCI_ERR_OTHER_END_TERMINATE_15 | 21 |
| HCI_ERR_CONNECTION_TERMINATE_LOCALLY | 22 |
| HCI_ERR_REPEATED_ATTEMPTS | 23 |
| HCI_ERR_PARING_NOT_ALLOWED | 24 |
| HCI_ERR_UNKNOWN_LMP_PDU | 25 |
| HCI_ERR_UNSUPPORTED_REMOTE_FEATURE | 26 |
| HCI_ERR_SCO_OFFSET_REJECTED | 27 |
| HCI_ERR_SCO_INTERVAL_REJECTED | 28 |
| HCI_ERR_SCO_AIR_MODE_REJECTED | 29 |
| HCI_ERR_INVALID_LMP_PARAMETERS | 30 |
| HCI_ERR_UNSPECIFIED_ERROR | 31 |
| HCI_ERR_UNSUPPORTED_LMP_PARAMETER_VAL | 32 |
| HCI_ERR_ROLE_CHANGE_NOT_ALLOWED | 33 |
| HCI_ERR_LMP_RESPONSE_TIMEOUT | 34 |
| HCI_ERR_LMP_ERROR_TRANSACTION_COLLISION | 35 |
| HCI_ERR_LMP_PDU_NOT_ALLOWED | 36 |
| HCI_ERR_ENCRYPTION_MODE_NOT_ACCEPTABLE | 37 |
| HCI_ERR_UNIT_KEY_USED | 38 |
| HCI_ERR_QOS_NOT_SUPPORTED | 39 |
| HCI_ERR_INSTANT_PASSED | 40 |
| HCI_ERR_PAIRING_WITH_UNIT_KEY_NOT_SUPP | 41 |
| HCI_ERR_ILLEGAL_HANDLE | 100 |
| HCI_ERR_TIMEOUT | 101 |
| HCI_ERR_OUTOFSYNC | 102 |
| HCI_ERR_NO_DESCRIPTOR | 103 |
Table 6-8. L2CAP Error Codes
| L2CAP Error | Code |
|---|---|
| L2CAP_NO_CAUSE | 0 |
| L2CAP_ERR_PENDING | 1 |
| L2CAP_ERR_REFUS_INV_PSM | 2 |
| L2CAP_ERR_REFUS_SEC_BLOCK | 3 |
| L2CAP_ERR_REFUS_NO_RESOURCE | 4 |
| L2CAP_ERR_TIMEOUT_EXTERNAL | 0xee |
Table 6-9. SDP Error Codes
| SDP Error | Code |
|---|---|
| SDP_ERR_RESERVED | 0 |
| SDP_ERR_UNSUPPORTED_SDP_VERSION | 1 |
| SDP_INVALID_SERVICE_RECORD_HANDLE | 2 |
| SDP_INVALID_REQUEST_SYNTAX | 3 |
| SDP_INVALID_PDU_SIZE | 4 |
| SDP_INVALID_CONTINUATION_STATE | 5 |
| SDP_INSUFFICIENT_RESOURCES | 6 |
| SDP_ERR_UNHANDLED_CODE | 100 |
| SDP_ERR_TIMEOUT | 101 |
| SDP_ERR_NOTFOUND | 102 |
| SDP_INVALID_RESPONSE_SYNTAX | 103 |
| SDP_NOT_FOUND (not really an error) | 200 |
Table 6-10. RFCOMM Error Codes
| RFCOMM Error | Code |
|---|---|
| RFCOMM_SUCCESS | 0 |
| RFCOMM_ERR_NORESOURCES | 1 |
| RFCOMM_ERR_ILL_PARAMETER | 2 |
| RFCOMM_ERR_REJECTED (Connection setup was rejected by remote side) | 100 |
| RFCOMM_ERR_TIMEOUT (Connection timed out) | 101 |
| RFCOMM_ERR_NSC (Non supported command received) | 102 |
| RFCOMM_ERR_ILLPARAMETER | 103 |
If the problems persist after restarting the communication parties, please contact Bluegiga Technologies as instructed in Section 1.2.
WRAP Access Server SDK contains libraries for making OBEX clients. However, before starting to implement a new client, it is strongly recommended to try out the obexput and obexget applications. It is very easy to call these applications from your own code, often removing completely the need to use the low level OBEX libraries.
The obexput application can be called with special parameters (- as bdaddr and 1 as channel) from the iWRAP interface, for example like this:
CALL bdaddr OBJP FORK "/usr/bin/obexput - 1 filename.ext" |
There are two libraries for making your own OBEX clients. See include/obex.h. libobex contains mostly low level functions and libobexclient high level functions. Their usage in practice can be studied using the source code of the obexbrowser application found in asdk/examples/obexbrowser/ directory.
| Warning |
If you write your own ObjP/FTP program using OBEX libraries, you have to get a Bluetooth profile certificate for it! obexput, obexget, obexserver and obexbrowser are already certified. |
| Warning |
OBEX libraries are not thread safe! You have to fork separate process for each connection. |
Initialize the OBEX library. Must be the first function called. s_in and s_out are data handles for reading and writing.
Deinitialize the OBEX library. Must be the last function called.
Receive one OBEX packet. You have to free() the received packet! If NULL is returned, you have to disconnect next (timeout, dead socket, ...). If timeout is zero, wait forever. If timeout is nonzero, wait up to timeout seconds.
Send one packet. Does not call free().
Initialize an OBEX packet to empty command type packet.
Add byte/long/unicode-string/binary/ascii data to an OBEX packet.
Find header data from an OBEX packet. Returns -1 if not found, otherwise the length of the data.
Return mime type for filename.
Connect to target UUID. Target can be NULL (Object Push connect). Returns 0 if no errors, -1 if timeout, -2 if broken socket, >0 if OBEX error (see IrDA Object Exchange Protocol by Infrared Data Association for OBEX response codes).
Disconnect. Returns 0 if no errors, -1 if timeout, -2 if broken socket, >0 if OBEX error (see IrDA Object Exchange Protocol by Infrared Data Association for OBEX response codes).
int obex_put(char * name, char * type, char * data, long * length, FILE * fdata, obex_progress_t
progress, void *
progressarg);
Put local file / data block to remote.
name is remote file name. Can be NULL.
type is remote MIME type. Can be NULL.
data/length are pointer to data block and length. Can be NULL/0.
fdata is file handle for local file, if data was NULL.
progress is a function to be called after each data block. Can be NULL. progressarg will be passed as parameter.
Returns 0 if no errors, -1 if timeout, -2 if broken socket, >0 the OBEX error code (see IrDA Object Exchange Protocol by Infrared Data Association for OBEX response codes).
int obex_get(char * name, char * type, char * data, long max_length, FILE * fdata, obex_progress_t
progress, void *
progressarg);
Get remote file to local.
name is remote file name. Can be NULL.
type remote MIME type. Can be NULL.
data/max_length are pointer to data block and length. Can be NULL/0.
fdata is file handle for local file, if data was NULL.
progress is a function to be called after each data block. Can be NULL. progressarg will be passed as parameter.
Returns >=0 (number of bytes received) if no errors, -1 if timeout, -2 if broken socket, <0 if OBEX error (see IrDA Object Exchange Protocol by Infrared Data Association for OBEX response codes).
Setpath to name with flags. Returns 0 if no errors, -1 if timeout, -2 if broken socket, >0 if OBEX error (see IrDA Object Exchange Protocol by Infrared Data Association for OBEX response codes).
The application obexbrowser is an Object Push Profile (ObjP) and File Transfer Profile (FTP) client, and is shipped with Access Server in both binary form (as it is part of the Access Server platform) and in source form (at it is a good example of using the OBEX libraries).
For an outgoing ObjP/FTP call you need to:
Make the outgoing RFCOMM call from iWRAP.
For example: CALL 00:07:80:80:bf:01 FTP RFCOMM
Run obexbrowser from the command line. It takes two parameters: hostname and port number. Hostname is usually localhost and port number can be read from the iWRAP server's CONNECT reply.
For example: obexbrowser localhost 1024
obexbrowser itself supports all the OBEX commands. See the source code and the IrDA Object Exchange Protocol by Infrared Data Association. The commands obexbrowser accepts are described in Table 6-11.
Table 6-11. obexbrowser Commands
| Command | Description |
|---|---|
| connect | Makes default INBOX connect (Object Push). |
| connect-ftp | Makes connect to FTP UUID. |
| disconnect | Disconnect. |
| cd/ | Setpath to root. |
| cd path | Setpath to path. |
| cd.. | Setpath with backup. |
| md path | Create subdirectory path. |
| put local remote | Put local to remote. Use - for local name to delete remote file. |
| get local remote | Get remote to local. |
| cat remote | Cat remote. |
| ls | Get mime x-obex/folder-listing without filename. |
Example:
iWRAP server:
READY.
CALL 00:07:80:80:bf:01 3 RFCOMM
CALL 0
RINGING 0
CONNECT 0 RFCOMM 1024
Command line:
obexbrowser localhost 1024
connect
connect=00
get remote.vcf -
get=143
put default.vcf
put=00
disconnect
disconnect=00
Ctrl-D
iWARP server:
NO CARRIER 0 ERROR 000
|
| <<< Previous | Home | Next >>> |
| Software Development Kit | I/O API |