Update: RFCOMM negotiation works now – connecting to the serial TTY device enables use of one of the Arduino Due UARTs. You can send short strings across the Bluetooth SPP link. The hexadecimal dump below was apparently a Bluetooth dongle hardware error code, one byte “0x37” (0x10 0x01 0x37). Documentation from CSR (look for the document CS-227432-SP-3-BCCMD-HQ, by searching for “HQ Commands”) told me this was a hardware fault code with a funny name:
FAULT_ALREADY_BAGSIED: Two subsystems are attempting to use the same .
The same what? The PDF contains exactly that text, “… the same .” Nuts. The documentation was leading me nowhere, but clearly the dongle was receiving command data I was sending to it, and going into fault condition as a result.
It turned out that I was sending an incomplete RFCOMM packet – I forgot to include the HCI handle for the existing ACL connection in the command I was sending. Aargh…!
So, it works now, after a fashion. I’m able to connect to the UART to send very short strings. Trying to send anything longer in either direction will crash the dongle HCI stack, which says there’s still something wrong with the code. Get the updated code here, as well as the driver sketch here.
Some good news: The Atmel Software Framework 3.12 allows interrupt-driven reads and writes from any of the Bluetooth dongle pipes – control, event, and bulk I/O. This is good. USB pipe communication is now non-blocking, no longer handled from the Arduino’s single flow-of-control path, driven from the Arduino main loop. When you write to a pipe, the call to enqueue a stream of bytes returns immediately. A callback function is called when the write succeeds (or goes to timeout; or when an error occurs). Similarly, reads from a pipe can be handled outside the main flow of your code. It was relatively straightforward to update the ASF framework files included with the Arduino nightly build (of which I’m using one of those that went into Arduino 1.5.4), involving minimal rewriting of the original ASF headers and source code. Arduino LLC use a small set of files from the complete ASF, which they use to create a statically linkable binary archive, that is used by the linker in assembling binaries uploaded to the Arduino Due.
There’s two parts to this code: The modified USBHost, and the mooshed together libsam code, which go into the Arduino tree. Find the locations of the USBHost library directory, and the libsam directory, and unpack the contents of both tar files there. The libsam code has to be compiled, by invoking
make -C build_gcc clean all
Warning: The code will definitely break Arduino Due scripts that rely on the standard USBHost classes. The Keyboard and Mouse classes are not implemented at all by this library, so you’ll want to keep a fresh copy of the Arduino IDE installer handy, to bring your IDE back to working shape for Arduino Due hacking. Merging this code into your Arduino IDE tree should not affect your experiments with other Arduino boards (non-SAM3X8E based models), as it creates libraries only used for compiling Arduino Due code.
An SDP record preprocessor allows use of C macros to define a Service Discovery Protocol service attribute search response in a programmer-friendly fashion – no need to manually compute data element sequence sizes. Individual data element sequences are assembled in the required general format, and a stack recursion method iterates through the array in memory, writing child content lengths into the parent data element’s size descriptors.
Also, every time a message is received from the Bluetooth dongle, the code now issues a Host Number of Completed Packets HCI command – this tells the RISC processor on the dongle that the Arduino has room in it’s internal buffers for more. Curiously, the Due probably doesn’t have that much more RAM than the dongle: If this dongle from Cambridge Silicon Radio has 48K, like their newer BlueCore devices do, then the Arduino Due has just twice that, at 96K; the HCI protocol takes this resource constraint into account, and has that command precisely to help both the host (Arduino) and dongle manage limited resources. Muy kewl. I remember this, and I imagine how much harder it would have been to program the Apollo spacecraft Guidance Computer, which only had 2 K-word (4 kilobytes today) RAM, and around 40K program memory. Hanep.
The upshot of these changes – incorporating ASF 3.12 libraries, rewriting the SDP public browse root response message, and sending the HNCP command, is that my notebook now recognizes the Arduino Due as a Bluetooth Serial Port device – yippee!
The SDP Service Search Attribute response used to be transmitted as in two chunks, and is now instead transmitted as a single record. This required bumping the L2CAP output buffer size from 64 bytes to a roomier 127 bytes.
Not Quite Yippee…
The result of this work is that pairing with the Arduino Due results in my notebook creating a character device /dev/tty.ArduinoDue-COM1. It would be great if it worked:
And on the Arduino IDE, I see my cobbled-together USBHost stack receiving a Set Asynchronous Balanced Mode (SABM) command, following which the code (basically the TKJ Electronics code) issuing an RFCOMM Unnumbered Acknowledgement response. The dongle appears to interpret that as some kind of reset. The ASF framework notifies my code that there’s been a change of USB bus state – the dongle disconnects and reconnects, and is successfully reenumerated. Then we get a stream of apparent gibberish that looks like an HCI hardware error event had just occurred.
Am stuck here at the moment.
Testable ideas for debugging:
Here are my guesses at what’s happening.
- The response I’m sending is being interpreted as a reset command. This comes from reading this bit from the CSR document BC419143B-ds-001Pe BlueCore4-Flash Plug-n-Go Data Sheet.pdf
A UART break condition can be used in three ways: 1. Presenting a UART break condition to the chip can force the chip to perform a hardware reboot 2. Presenting a break condition at boot time can hold the chip in a low power state, preventing normal initialisation while the condition exists 3. With BCSP, the firmware can be configured to send a break to the host before sending data. (This is normally used to wake the host from a Deep Sleep state.)
- I’ve made some fundamental mistake in how my code handles output buffers. Probably something like an off-by-one accessing unsigned char arrays, so that I’m sending a corrupt byte stream to the dongle;
- The Atmel Software Framework code is issuing a bus detach because of something that happens either in the interrupt handling flow of control, or in the normal processing of the Arduino work loop.