diff --git a/inc/MicroBit.h b/inc/MicroBit.h index cdd23d7..b218210 100644 --- a/inc/MicroBit.h +++ b/inc/MicroBit.h @@ -36,6 +36,7 @@ #include "MicroBitDFUService.h" #include "MicroBitEventService.h" #include "MicroBitLEDService.h" +#include "MicroBitAccelerometerService.h" #include "ExternalEvents.h" // MicroBit::flags values @@ -105,10 +106,11 @@ class MicroBit MicroBitIO io; // Bluetooth related member variables. - BLEDevice *ble; - MicroBitDFUService *ble_firmware_update_service; - MicroBitEventService *ble_event_service; - MicroBitLEDService *ble_led_service; + BLEDevice *ble; + MicroBitDFUService *ble_firmware_update_service; + MicroBitEventService *ble_event_service; + MicroBitLEDService *ble_led_service; + MicroBitAccelerometerService *ble_accelerometer_service; /** * Constructor. diff --git a/inc/MicroBitAccelerometer.h b/inc/MicroBitAccelerometer.h index b9cbc4f..7456177 100644 --- a/inc/MicroBitAccelerometer.h +++ b/inc/MicroBitAccelerometer.h @@ -36,6 +36,10 @@ #define MMA8653_SAMPLE_RANGES 3 #define MMA8653_SAMPLE_RATES 8 +/* + * Accelerometer events + */ +#define MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE 1 struct MMA8653Sample { diff --git a/inc/MicroBitAccelerometerService.h b/inc/MicroBitAccelerometerService.h index 65dc5d6..e9567d4 100644 --- a/inc/MicroBitAccelerometerService.h +++ b/inc/MicroBitAccelerometerService.h @@ -24,12 +24,18 @@ class MicroBitAccelerometerService */ MicroBitAccelerometerService(BLEDevice &_ble); + + private: + /** * Callback. Invoked when any of our attributes are written via BLE. */ void onDataWritten(const GattWriteCallbackParams *params); - private: + /** + * Accelerometer update callback + */ + void accelerometerUpdate(MicroBitEvent e); // Bluetooth stack we're running on. BLEDevice &ble; diff --git a/inc/MicroBitCompass.h b/inc/MicroBitCompass.h index 3863f71..b89e0e9 100644 --- a/inc/MicroBitCompass.h +++ b/inc/MicroBitCompass.h @@ -36,12 +36,26 @@ #define MAG_CTRL_REG1 0x10 #define MAG_CTRL_REG2 0x11 +/** + * Configuration options + */ +struct MAG3110SampleRateConfig +{ + uint32_t sample_period; + uint8_t ctrl_reg1; +}; + +extern const MAG3110SampleRateConfig MAG3110SampleRate[]; + +#define MAG3110_SAMPLE_RATES 11 + /* * Compass events */ #define MICROBIT_COMPASS_EVT_CAL_REQUIRED 1 #define MICROBIT_COMPASS_EVT_CAL_START 2 #define MICROBIT_COMPASS_EVT_CAL_END 3 +#define MICROBIT_COMPASS_EVT_DATA_UPDATE 4 /* * Status Bits @@ -85,9 +99,9 @@ class MicroBitCompass : public MicroBitComponent * Used to track asynchronous events in the event bus. */ - uint16_t address; // I2C address of the magnetmometer. - - unsigned long eventStartTime; // used to store the current system clock when async calibration has started + uint16_t address; // I2C address of the magnetmometer. + uint16_t samplePeriod; // The time between samples, in millseconds. + unsigned long eventStartTime; // used to store the current system clock when async calibration has started public: @@ -116,7 +130,29 @@ class MicroBitCompass : public MicroBitComponent * @endcode */ MicroBitCompass(uint16_t id, uint16_t address); - + + /** + * Configures the compass for the sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + */ + void configure(); + + /** + * Attempts to set the sample rate of the compass to the specified value (in ms). + * n.b. the requested rate may not be possible on the hardware. In this case, the + * nearest lower rate is chosen. + * @param period the requested time between samples, in milliseconds. + */ + void setPeriod(int period); + + /** + * Reads the currently configured sample rate of the compass. + * @return The time between samples, in milliseconds. + */ + int getPeriod(); + /** * Gets the current heading of the device, relative to magnetic north. * @return the current heading, in degrees. diff --git a/inc/MicroBitConfig.h b/inc/MicroBitConfig.h index 03f4e1f..79cea2d 100644 --- a/inc/MicroBitConfig.h +++ b/inc/MicroBitConfig.h @@ -160,6 +160,12 @@ #define MICROBIT_BLE_LED_SERVICE 1 #endif +// Enable/Disable BLE Service: MicroBitAccelerometerService +// This enables live access to the on board 3 axis accelerometer. +// Set '1' to enable. +#ifndef MICROBIT_BLE_ACCELEROMETER_SERVICE +#define MICROBIT_BLE_ACCELEROMETER_SERVICE 1 +#endif // Defines the maximum length strong that can be written to the // display over BLE. diff --git a/source/MicroBit.cpp b/source/MicroBit.cpp index 2faec40..66a0e75 100644 --- a/source/MicroBit.cpp +++ b/source/MicroBit.cpp @@ -121,6 +121,10 @@ void MicroBit::init() ble_led_service = new MicroBitLEDService(*ble); #endif +#if CONFIG_ENABLED(MICROBIT_BLE_ACCELEROMETER_SERVICE) + ble_accelerometer_service = new MicroBitAccelerometerService(*ble); +#endif + // Setup advertising. ble->accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); ble->accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)MICROBIT_BLE_DEVICE_NAME, sizeof(MICROBIT_BLE_DEVICE_NAME)); diff --git a/source/MicroBitAccelerometer.cpp b/source/MicroBitAccelerometer.cpp index c87e117..18524a3 100644 --- a/source/MicroBitAccelerometer.cpp +++ b/source/MicroBitAccelerometer.cpp @@ -174,7 +174,8 @@ void MicroBitAccelerometer::update() sample.y *= this->sampleRange; sample.z *= this->sampleRange; - //TODO: Issue an event. + // Indicate that a new sample is available + MicroBitEvent e(id, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE); }; /** @@ -263,7 +264,7 @@ int MicroBitAccelerometer::getZ() { return sample.z; } - + /** * periodic callback from MicroBit clock. diff --git a/source/MicroBitCompass.cpp b/source/MicroBitCompass.cpp index 42bb755..245e27e 100644 --- a/source/MicroBitCompass.cpp +++ b/source/MicroBitCompass.cpp @@ -32,8 +32,9 @@ MicroBitCompass::MicroBitCompass(uint16_t id, uint16_t address) : average(), sam // Enable automatic reset after each sample; writeCommand(MAG_CTRL_REG2, 0xA0); - // Select 10Hz update rate, with oversampling. Also enables the device. - writeCommand(MAG_CTRL_REG1, 0x61); + // Select 10Hz update rate, with oversampling, and enable the device. + this->samplePeriod = 100; + this->configure(); //fetch our previous average values average.x = read16(MAG_OFF_X_MSB); @@ -174,6 +175,11 @@ void MicroBitCompass::idleTick() eventStartTime = 0; calibrateEnd(); } + } + else + { + // Indicate that a new sample is available + MicroBitEvent e(id, MICROBIT_COMPASS_EVT_DATA_UPDATE); } } } @@ -220,6 +226,56 @@ int MicroBitCompass::getZ() return sample.z; } +/** + * Configures the compass for the sample rate defined + * in this object. The nearest values are chosen to those defined + * that are supported by the hardware. The instance variables are then + * updated to reflect reality. + */ +void MicroBitCompass::configure() +{ + const MAG3110SampleRateConfig *actualSampleRate; + + // First find the nearest sample rate to that specified. + actualSampleRate = &MAG3110SampleRate[MAG3110_SAMPLE_RATES-1]; + for (int i=MAG3110_SAMPLE_RATES-1; i>=0; i--) + { + if(MAG3110SampleRate[i].sample_period < this->samplePeriod * 1000) + break; + + actualSampleRate = &MAG3110SampleRate[i]; + } + + // OK, we have the correct data. Update our local state. + this->samplePeriod = actualSampleRate->sample_period / 1000; + + // Bring the device online, with the requested sample frequency. + writeCommand(MAG_CTRL_REG1, actualSampleRate->ctrl_reg1 | 0x01); +} + + +/** + * Attempts to set the sample rate of the compass to the specified value (in ms). + * n.b. the requested rate may not be possible on the hardware. In this case, the + * nearest lower rate is chosen. + * @param period the requested time between samples, in milliseconds. + */ +void MicroBitCompass::setPeriod(int period) +{ + this->samplePeriod = period; + this->configure(); +} + +/** + * Reads the currently configured sample rate of the compass. + * @return The time between samples, in milliseconds. + */ +int MicroBitCompass::getPeriod() +{ + return (int)samplePeriod; +} + + /** * Attempts to determine the 8 bit ID from the magnetometer. * @return the id of the compass (magnetometer) @@ -333,6 +389,21 @@ void MicroBitCompass::clearCalibration() */ int MicroBitCompass::isIdleCallbackNeeded() { - //Active HI + // The MAG3110 raises an interrupt line when data is ready, which we sample here. + // The interrupt line is active HI, so simply return the state of the pin. return int1; } + +const MAG3110SampleRateConfig MAG3110SampleRate[MAG3110_SAMPLE_RATES] = { + {12500, 0x00}, // 80 Hz + {25000, 0x20}, // 40 Hz + {50000, 0x40}, // 20 Hz + {100000, 0x60}, // 10 hz + {200000, 0x80}, // 5 hz + {400000, 0x81}, // 2.5 hz + {800000, 0x82}, // 1.25 hz + {1600000, 0xb0}, // 0.63 hz + {3200000, 0xd0}, // 0.31 hz + {6400000, 0xf0}, // 0.16 hz + {12800000, 0xf1} // 0.08 hz +}; diff --git a/source/ble-services/MicroBitAccelerometerService.cpp b/source/ble-services/MicroBitAccelerometerService.cpp index 874a3a6..c846b34 100644 --- a/source/ble-services/MicroBitAccelerometerService.cpp +++ b/source/ble-services/MicroBitAccelerometerService.cpp @@ -42,9 +42,9 @@ MicroBitAccelerometerService::MicroBitAccelerometerService(BLEDevice &_ble) : ble.updateCharacteristicValue(accelerometerPeriodCharacteristicHandle, (const uint8_t *)&accelerometerPeriodCharacteristicBuffer, sizeof(accelerometerPeriodCharacteristicBuffer)); ble.onDataWritten(this, &MicroBitAccelerometerService::onDataWritten); + uBit.MessageBus.listen(MICROBIT_ID_ACCELEROMETER, MICROBIT_ACCELEROMETER_EVT_DATA_UPDATE, this, &MicroBitAccelerometerService::accelerometerUpdate, MESSAGE_BUS_LISTENER_NONBLOCKING | MESSAGE_BUS_LISTENER_URGENT); } - /** * Callback. Invoked when any of our attributes are written via BLE. */ @@ -57,6 +57,17 @@ void MicroBitAccelerometerService::onDataWritten(const GattWriteCallbackParams * } } +/** + * Accelerometer update callback + */ +void MicroBitAccelerometerService::accelerometerUpdate(MicroBitEvent e) +{ + accelerometerDataCharacteristicBuffer[0] = uBit.accelerometer.getX(); + accelerometerDataCharacteristicBuffer[1] = uBit.accelerometer.getY(); + accelerometerDataCharacteristicBuffer[2] = uBit.accelerometer.getZ(); + + ble.gattServer().notify(accelerometerDataCharacteristicHandle,(uint8_t *)accelerometerDataCharacteristicBuffer, sizeof(accelerometerDataCharacteristicBuffer)); +} const uint8_t MicroBitAccelerometerServiceUUID[] = { 0xe9,0x5d,0x07,0x53,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8