Hi guys.
I'm trying to use an Arduino 101 as a Bluetooth Mouse. I'm trying to base the reports on accelerometer movement. However, while I can connect it to my Android phone, I can't get a cursor to show up. It will show up as an input device, but no cursor. I tried a commercial Bluetooth mouse, which did cause a cursor to show up on connection. I've been bashing my head against the wall for a few days, but I can't seem to get it to work.
Maybe someone more experienced on here can show me what I've done wrong.
I'm attempting to use the HID over GATT profile.
So I have the following services and characteristics
HID Service (0x1812)
- Protocol Model (0x2A42)
- Boot Mouse Report (0x2A33)
- HID Information (0x2A4A)
- HID Report Map (0x2A4B)
- HID Control Point (0x2A4C)
- Report (0x2A4D)
Battery Service (0x180F)
- Battery Level (0x2A19)
Device Information (0x180A)
- PnP ID (0x2A50)
Thanks guys!
#include "CurieIMU.h"
#include "CurieBLE.h"
int ax, ay, az; // accelerometer values
//Defining Bluetooth Peripheral (this board)
BLEPeripheral blePeripheral;
//Defining HID Serivce
BLEService hidService("1812"); // declare it as an HID device
BLECharCharacteristic bootModeProtocol("2A42", BLERead | BLEWriteWithoutResponse);
BLECharacteristic bootMouseReport("2A33", BLERead | BLENotify,3);//Seting up the mouse specific characteristic
BLECharacteristic hidInformation("2A4A",BLERead, 4 );
BLECharacteristic reportMap("2A4B", BLERead,50);
BLECharCharacteristic controlPoint("2A4C",BLEWriteWithoutResponse);
BLECharacteristic mouseReport("2A4D", BLERead | BLENotify, 3); //the report value
//Defining Battery Service
BLEService batteryService("180F");
BLECharCharacteristic batteryLevel("2A19", BLERead);
//Device Information Service
BLEService deviceInformation("180A");
BLECharacteristic pnpID("2A50", BLERead, 7);
const int ledPin = 13; // activity LED pin
int calibrateOffsets = 1; // int to determine whether calibration takes place or not
long prevmill;
int lastx;
int lasty;
unsigned char bleValue[3] = {0x00, 0x00, 0x00};
unsigned char reportMapValue[50] = {0x05,0x01,0x09,0x02,0xA1,0x01,0x09,0x01,0xA1,0x00,0x05,0x09,0x19,0x01,0x29,0x03,0x15,0x00,0x25,0x01,0x95,0x03,0x75,0x01,0x81,0x02,0x95,0x01,0x75,0x05,0x81,0x01,0x05,0x01,0x09,0x30,0x09,0x31,0x15,0x81,0x25,0x7F,0x75,0x08,0x95,0x02,0x81,0x06,0xC0,0xC0};
const unsigned char bootMode = 0x00;
const unsigned char batteryDummy = 0x63;
unsigned char hidInfo[3] = {'0112', 0x00, 0xc0};
unsigned char pnp[4] = {0x02, 0x0000, 0x0000, 0x1234};
float prevspeedx;
float prevspeedy;
float currentspeedx;
float currentspeedy;
byte movex;
byte movey;
void setup() {
Serial.begin(9600); // initialize Serial communication
while (!Serial); // wait for the serial port to open
// initialize device
Serial.println("Initializing IMU device...");
CurieIMU.begin();
CurieIMU.setAccelerometerRate(200);
CurieIMU.setAccelerometerRange(2);
// verify connection
Serial.println("Testing device connections...");
if (CurieIMU.begin()) {
Serial.println("CurieIMU connection successful");
} else {
Serial.println("CurieIMU connection failed");
}
// use the code below to calibrate accel/gyro offset values
if (calibrateOffsets == 1) {
Serial.println("Internal sensor offsets BEFORE calibration...");
Serial.print(CurieIMU.getAccelerometerOffset(X_AXIS));
Serial.print("\t"); // -76
Serial.print(CurieIMU.getAccelerometerOffset(Y_AXIS));
Serial.print("\t"); // -235
Serial.println(CurieIMU.getAccelerometerOffset(Z_AXIS));
Serial.println("About to calibrate. Make sure your board is stable and upright");
delay(5000);
Serial.print("Starting Acceleration calibration and enabling offset compensation...");
CurieIMU.autoCalibrateAccelerometerOffset(X_AXIS, 0);
CurieIMU.autoCalibrateAccelerometerOffset(Y_AXIS, 0);
CurieIMU.autoCalibrateAccelerometerOffset(Z_AXIS, 1);
Serial.println(" Done");
Serial.println("Internal sensor offsets AFTER calibration...");
Serial.print(CurieIMU.getAccelerometerOffset(X_AXIS));
Serial.print("\t"); // -76
Serial.print(CurieIMU.getAccelerometerOffset(Y_AXIS));
Serial.print("\t"); // -2359
Serial.println(CurieIMU.getAccelerometerOffset(Z_AXIS));
}
// configure Arduino LED for activity indicator
pinMode(ledPin, OUTPUT);
// Add service name and UUID for bluetooth
blePeripheral.setLocalName("stylus");
blePeripheral.setAdvertisedServiceUuid(hidService.uuid());
// Add services and characteristics
//HID Service and Characteristics
blePeripheral.addAttribute(hidService);
Serial.println("adding HID Service");
blePeripheral.addAttribute(bootMouseReport);
Serial.println("bootMouseReport added");
blePeripheral.addAttribute(bootModeProtocol);
blePeripheral.addAttribute(hidInformation);
blePeripheral.addAttribute(reportMap);
blePeripheral.addAttribute(controlPoint);
blePeripheral.addAttribute(mouseReport);
//Battery service and characteristic
blePeripheral.addAttribute(batteryService);
blePeripheral.addAttribute(batteryLevel);
//Device Information
blePeripheral.addAttribute(deviceInformation);
blePeripheral.addAttribute(pnpID);
// Setting the initial value for our mouse input
bootModeProtocol.setValue('0');
bootMouseReport.setValue(bleValue,3);
Serial.print("boot mouse report value: ");
Serial.print(bleValue[0]);
Serial.print(bleValue[1]);
Serial.print(bleValue[2]);
batteryLevel.setValue(batteryDummy);
hidInformation.setValue(hidInfo, 4);
pnpID.setValue(pnp, 7);
reportMap.setValue(reportMapValue,50);
mouseReport.setValue(bleValue,3);
blePeripheral.setAppearance(962);
// Starting the service
blePeripheral.begin();
Serial.println("Bluetooth device active, waiting for connections...");
prevmill = millis();
prevspeedx = 0;
prevspeedy = 0;
currentspeedx = 0;
currentspeedy = 0;
lastx = 0;
lasty = 0;
// look for central device to connect
BLECentral central = blePeripheral.central();
Serial.print("Connecting to central: ");
// print the central's MAC address
Serial.println(central.address());
}
void loop() {
long currentmill = millis();
int hertz = 200;
if (currentmill - prevmill >= 1000 / hertz) {
// look for central device to connect
BLECentral central = blePeripheral.central();
// if a central is connected then we start to do things
if (central) {
// read raw accel/gyro measurements from device
CurieIMU.readAccelerometer(ax, ay, az);
currentspeedx = prevspeedx + (54 * ax);
currentspeedy = prevspeedy + (54 * ay);
Serial.print(ay / 258);
Serial.print("\t");
Serial.println((az - 16384) / 258);
movex = byte(floor(ay / 258));
movey = byte(floor((az - 16384) / 258));
bleValue[1] = movex;
bleValue[2] = movey;
bootMouseReport.setValue(bleValue,3);
prevspeedx = currentspeedx;
prevspeedy = currentspeedy;
prevmill = currentmill;
}
}
}
Also, some links that you might find helpful:
http://www.usb.org/developers/hidpage/HID1_11.pdf
https://www.arduino.cc/en/Reference/CurieBLE
https://www.bluetooth.com/specifications/gatt
I've read or at least scanned most of this stuff, but there's likely something I've missed.