mbed.org local branch of microbit-dal. The real version lives in git at https://github.com/lancaster-university/microbit-dal

Dependencies:   BLE_API nRF51822 mbed-dev-bin

Dependents:   microbit Microbit IoTChallenge1 microbit ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBitLightSensor.cpp Source File

MicroBitLightSensor.cpp

00001 /*
00002 The MIT License (MIT)
00003 
00004 Copyright (c) 2016 British Broadcasting Corporation.
00005 This software is provided by Lancaster University by arrangement with the BBC.
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a
00008 copy of this software and associated documentation files (the "Software"),
00009 to deal in the Software without restriction, including without limitation
00010 the rights to use, copy, modify, merge, publish, distribute, sublicense,
00011 and/or sell copies of the Software, and to permit persons to whom the
00012 Software is furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
00020 THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
00021 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
00022 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
00023 DEALINGS IN THE SOFTWARE.
00024 */
00025 
00026 /**
00027   * Class definition for MicroBitLightSensor.
00028   *
00029   * This is an object that interleaves light sensing with MicroBitDisplay.
00030   */
00031 
00032 #include "MicroBitConfig.h"
00033 #include "MicroBitLightSensor.h"
00034 #include "MicroBitDisplay.h"
00035 
00036 /**
00037   * After the startSensing method has been called, this method will be called
00038   * MICROBIT_LIGHT_SENSOR_AN_SET_TIME after.
00039   *
00040   * It will then read from the currently selected channel using the AnalogIn
00041   * that was configured in the startSensing method.
00042   */
00043 void MicroBitLightSensor::analogReady()
00044 {
00045     this->results[chan] = this->sensePin->read_u16();
00046 
00047     analogDisable();
00048 
00049     DigitalOut((PinName)(matrixMap.columnStart + chan)).write(1);
00050 
00051     chan++;
00052 
00053     chan = chan % MICROBIT_LIGHT_SENSOR_CHAN_NUM;
00054 }
00055 
00056 /**
00057   * Forcibly disables the AnalogIn, otherwise it will remain in possession
00058   * of the GPIO channel it is using, meaning that the display will not be
00059   * able to use a channel (COL).
00060   *
00061   * This is required as per PAN 3, details of which can be found here:
00062   *
00063   * https://www.nordicsemi.com/eng/nordic/download_resource/24634/5/88440387
00064   */
00065 void MicroBitLightSensor::analogDisable()
00066 {
00067     NRF_ADC->ENABLE = ADC_ENABLE_ENABLE_Disabled;
00068 
00069     NRF_ADC->CONFIG = (ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos) |
00070                       (ADC_CONFIG_INPSEL_SupplyTwoThirdsPrescaling << ADC_CONFIG_INPSEL_Pos) |
00071                       (ADC_CONFIG_REFSEL_VBG                       << ADC_CONFIG_REFSEL_Pos) |
00072                       (ADC_CONFIG_PSEL_Disabled                    << ADC_CONFIG_PSEL_Pos) |
00073                       (ADC_CONFIG_EXTREFSEL_None                   << ADC_CONFIG_EXTREFSEL_Pos);
00074 }
00075 
00076 /**
00077   * Constructor.
00078   *
00079   * Create a representation of the light sensor.
00080   *
00081   * @param map The mapping information that relates pin inputs/outputs to physical screen coordinates.
00082   *            Defaults to microbitMatrixMap, defined in MicroBitMatrixMaps.h.
00083   */
00084 MicroBitLightSensor::MicroBitLightSensor(const MatrixMap &map) :
00085     analogTrigger(),
00086     matrixMap(map)
00087 {
00088     this->chan = 0;
00089 
00090     for(int i = 0; i < MICROBIT_LIGHT_SENSOR_CHAN_NUM; i++)
00091         results[i] = 0;
00092 
00093     if (EventModel::defaultEventBus)
00094         EventModel::defaultEventBus->listen(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing, MESSAGE_BUS_LISTENER_IMMEDIATE);
00095 
00096     this->sensePin = NULL;
00097 }
00098 
00099 /**
00100   * This method returns a summed average of the three sections of the display.
00101   *
00102   * A section is defined as:
00103   *  ___________________
00104   * | 1 |   | 2 |   | 3 |
00105   * |___|___|___|___|___|
00106   * |   |   |   |   |   |
00107   * |___|___|___|___|___|
00108   * | 2 |   | 3 |   | 1 |
00109   * |___|___|___|___|___|
00110   * |   |   |   |   |   |
00111   * |___|___|___|___|___|
00112   * | 3 |   | 1 |   | 2 |
00113   * |___|___|___|___|___|
00114   *
00115   * Where each number represents a different section on the 5 x 5 matrix display.
00116   *
00117   * @return returns a value in the range 0 - 255 where 0 is dark, and 255
00118   * is very bright
00119   */
00120 int MicroBitLightSensor::read()
00121 {
00122     int sum = 0;
00123 
00124     for(int i = 0; i < MICROBIT_LIGHT_SENSOR_CHAN_NUM; i++)
00125         sum += results[i];
00126 
00127     int average = sum / MICROBIT_LIGHT_SENSOR_CHAN_NUM;
00128 
00129     average = min(average, MICROBIT_LIGHT_SENSOR_MAX_VALUE);
00130 
00131     average = max(average, MICROBIT_LIGHT_SENSOR_MIN_VALUE);
00132 
00133     int inverted = (MICROBIT_LIGHT_SENSOR_MAX_VALUE - average) + MICROBIT_LIGHT_SENSOR_MIN_VALUE;
00134 
00135     int a = 0;
00136 
00137     int b = 255;
00138 
00139     int normalised = a + ((((inverted - MICROBIT_LIGHT_SENSOR_MIN_VALUE)) * (b - a))/ (MICROBIT_LIGHT_SENSOR_MAX_VALUE - MICROBIT_LIGHT_SENSOR_MIN_VALUE));
00140 
00141     return normalised;
00142 }
00143 
00144 /**
00145   * The method that is invoked by sending MICROBIT_DISPLAY_EVT_LIGHT_SENSE
00146   * using the id MICROBIT_ID_DISPLAY.
00147   *
00148   * @note this can be manually driven by calling this member function, with
00149   *       a MicroBitEvent using the CREATE_ONLY option of the MicroBitEvent
00150   *       constructor.
00151   */
00152 void MicroBitLightSensor::startSensing(MicroBitEvent)
00153 {
00154     for(int rowCount = 0; rowCount < matrixMap.rows; rowCount++)
00155         DigitalOut((PinName)(matrixMap.rowStart + rowCount)).write(0);
00156 
00157     PinName currentPin = (PinName)(matrixMap.columnStart + chan);
00158 
00159     DigitalOut(currentPin).write(1);
00160 
00161     DigitalIn(currentPin, PullNone).~DigitalIn();
00162 
00163     if(this->sensePin != NULL)
00164         delete this->sensePin;
00165 
00166     this->sensePin = new AnalogIn(currentPin);
00167 
00168     analogTrigger.attach_us(this, &MicroBitLightSensor::analogReady, MICROBIT_LIGHT_SENSOR_AN_SET_TIME);
00169 }
00170 
00171 /**
00172   * A destructor for MicroBitLightSensor.
00173   *
00174   * The destructor removes the listener, used by MicroBitLightSensor from the default EventModel.
00175   */
00176 MicroBitLightSensor::~MicroBitLightSensor()
00177 {
00178     if (EventModel::defaultEventBus)
00179         EventModel::defaultEventBus->ignore(MICROBIT_ID_DISPLAY, MICROBIT_DISPLAY_EVT_LIGHT_SENSE, this, &MicroBitLightSensor::startSensing);
00180 }