diff --git a/inc/core/MicroBitComponent.h b/inc/core/MicroBitComponent.h index 62661e0c..76a37444 100644 --- a/inc/core/MicroBitComponent.h +++ b/inc/core/MicroBitComponent.h @@ -35,6 +35,7 @@ DEALINGS IN THE SOFTWARE. #define MICROBIT_ID_ACCELEROMETER 4 #define MICROBIT_ID_COMPASS 5 #define MICROBIT_ID_DISPLAY 6 +#define MICROBIT_ID_LIGHT_SENSOR 7 //EDGE connector events #define MICROBIT_IO_PINS 20 diff --git a/inc/drivers/MicroBitDisplay.h b/inc/drivers/MicroBitDisplay.h index cd6c6282..4ed12e01 100644 --- a/inc/drivers/MicroBitDisplay.h +++ b/inc/drivers/MicroBitDisplay.h @@ -627,13 +627,17 @@ class MicroBitDisplay : public MicroBitComponent * This also changes the tickPeriod to MICROBIT_LIGHT_SENSOR_TICK_SPEED so * that the display does not suffer from artifacts. * + * @param valid_only True to return -1 if full set of results not taken and to return a stale + * but valid reading in the case of invalid results. False to use all results. + * Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h. + * * @return an indicative light level in the range 0 - 255. * * @note this will return 0 on the first call to this method, a light reading * will be available after the display has activated the light sensor for the * first time. */ - int readLightLevel(); + int readLightLevel(bool valid_only = false); /** * Destructor for MicroBitDisplay, where we deregister this instance from the array of system components. diff --git a/inc/drivers/MicroBitLightSensor.h b/inc/drivers/MicroBitLightSensor.h index 51698e2a..ebf03187 100644 --- a/inc/drivers/MicroBitLightSensor.h +++ b/inc/drivers/MicroBitLightSensor.h @@ -32,12 +32,17 @@ DEALINGS IN THE SOFTWARE. #include "EventModel.h" #include "MicroBitMatrixMaps.h" -#define MICROBIT_LIGHT_SENSOR_CHAN_NUM 3 -#define MICROBIT_LIGHT_SENSOR_AN_SET_TIME 4000 -#define MICROBIT_LIGHT_SENSOR_TICK_PERIOD 5 +/** + * Event codes raised by MicroBitDisplay + */ +#define MICROBIT_DISPLAY_EVT_LIGHT_SENSE_READY 1 + +#define MICROBIT_LIGHT_SENSOR_CHAN_NUM 3 +#define MICROBIT_LIGHT_SENSOR_AN_SET_TIME 4000 +#define MICROBIT_LIGHT_SENSOR_TICK_PERIOD 5 -#define MICROBIT_LIGHT_SENSOR_MAX_VALUE 338 -#define MICROBIT_LIGHT_SENSOR_MIN_VALUE 75 +#define MICROBIT_LIGHT_SENSOR_MAX_VALUE 338 +#define MICROBIT_LIGHT_SENSOR_MIN_VALUE 75 /** * Class definition for MicroBitLightSensor. @@ -50,6 +55,12 @@ class MicroBitLightSensor //contains the results from each section of the display int results[MICROBIT_LIGHT_SENSOR_CHAN_NUM]; + // The average of the three results. + int average; + + // The average of the three results the last time all results were valid. + int valid_average; + //holds the current channel (also used to index the results array) uint8_t chan; @@ -81,6 +92,15 @@ class MicroBitLightSensor */ void analogDisable(); + /** + * This method updates the average of the three results, as well as the valid_average + * if results are valid. The MICROBIT_DISPLAY_EVT_LIGHT_SENSE_READY event is sent if + * the valid_average is updated. + * + * @return returns a boolean representing whether or not the results are valid. + */ + bool update_averages(); + public: /** @@ -111,10 +131,14 @@ class MicroBitLightSensor * * Where each number represents a different section on the 5 x 5 matrix display. * + * @param valid_only True to return -1 if full set of results not taken and to return a stale + * but valid reading in the case of invalid results. False to use all results. + * Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h. + * * @return returns a value in the range 0 - 255 where 0 is dark, and 255 * is very bright */ - int read(); + int read(bool valid_only = false); /** * The method that is invoked by sending MICROBIT_DISPLAY_EVT_LIGHT_SENSE diff --git a/source/drivers/MicroBitDisplay.cpp b/source/drivers/MicroBitDisplay.cpp index d0d7b844..685bc154 100644 --- a/source/drivers/MicroBitDisplay.cpp +++ b/source/drivers/MicroBitDisplay.cpp @@ -1210,13 +1210,17 @@ MicroBitImage MicroBitDisplay::screenShot() * This also changes the tickPeriod to MICROBIT_LIGHT_SENSOR_TICK_SPEED so * that the display does not suffer from artifacts. * + * @param valid_only True to return -1 if full set of results not taken and to return a stale + * but valid reading in the case of invalid results. False to use all results. + * Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h. + * * @return an indicative light level in the range 0 - 255. * - * @note this will return 0 on the first call to this method, a light reading - * will be available after the display has activated the light sensor for the - * first time. + * @note this will return 255 (previously said 0, which was incorrect) + * on the first call to this method, a light reading will be available + * after the display has activated the light sensor for the first time. */ -int MicroBitDisplay::readLightLevel() +int MicroBitDisplay::readLightLevel(bool valid_only) { if(mode != DISPLAY_MODE_BLACK_AND_WHITE_LIGHT_SENSE) { @@ -1224,7 +1228,7 @@ int MicroBitDisplay::readLightLevel() this->lightSensor = new MicroBitLightSensor(matrixMap); } - return this->lightSensor->read(); + return this->lightSensor->read(valid_only); } /** diff --git a/source/drivers/MicroBitLightSensor.cpp b/source/drivers/MicroBitLightSensor.cpp index 3ceee2cc..7a7ffc77 100644 --- a/source/drivers/MicroBitLightSensor.cpp +++ b/source/drivers/MicroBitLightSensor.cpp @@ -51,6 +51,8 @@ void MicroBitLightSensor::analogReady() chan++; chan = chan % MICROBIT_LIGHT_SENSOR_CHAN_NUM; + + update_averages(); } /** @@ -87,8 +89,10 @@ MicroBitLightSensor::MicroBitLightSensor(const MatrixMap &map) : { this->chan = 0; + valid_average = -1; + for(int i = 0; i < MICROBIT_LIGHT_SENSOR_CHAN_NUM; i++) - results[i] = 0; + results[i] = -1; if (EventModel::defaultEventBus) EventModel::defaultEventBus->listen(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing, MESSAGE_BUS_LISTENER_IMMEDIATE); @@ -96,6 +100,32 @@ MicroBitLightSensor::MicroBitLightSensor(const MatrixMap &map) : this->sensePin = NULL; } +/** + * This method updates the average of the three results, as well as the valid_average + * if results are valid. The MICROBIT_DISPLAY_EVT_LIGHT_SENSE_READY event is sent if + * the valid_average is updated. + * + * @return returns a boolean representing whether or not the results are valid. + */ +bool MicroBitLightSensor::update_averages() +{ + bool valid = true; + int sum = 0; + for(int i = 0; i < MICROBIT_LIGHT_SENSOR_CHAN_NUM; i++) { + if (this->results[i] < 0 || this->results[i] > 450) { + valid = false; + } + // Use zero if a result hasn't been used rather than -1. + sum += max(this->results[i], 0); + } + this->average = sum / MICROBIT_LIGHT_SENSOR_CHAN_NUM; + if (valid) { + this->valid_average = this->average; + MicroBitEvent(MICROBIT_ID_LIGHT_SENSOR, MICROBIT_DISPLAY_EVT_LIGHT_SENSE_READY); + } + return valid; +} + /** * This method returns a summed average of the three sections of the display. * @@ -114,17 +144,19 @@ MicroBitLightSensor::MicroBitLightSensor(const MatrixMap &map) : * * Where each number represents a different section on the 5 x 5 matrix display. * + * @param valid_only True to return -1 if full set of results not taken and to return a stale + * but valid reading in the case of invalid results. False to use all results. + * Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h. + * * @return returns a value in the range 0 - 255 where 0 is dark, and 255 * is very bright */ -int MicroBitLightSensor::read() +int MicroBitLightSensor::read(bool valid_only) { - int sum = 0; - - for(int i = 0; i < MICROBIT_LIGHT_SENSOR_CHAN_NUM; i++) - sum += results[i]; + int average = valid_only ? this->valid_average : this->average; - int average = sum / MICROBIT_LIGHT_SENSOR_CHAN_NUM; + if (valid_only && average < 0) + return -1; average = min(average, MICROBIT_LIGHT_SENSOR_MAX_VALUE);