Eddystone test using modified DAL

Dependencies:   BLE_API mbed-dev-bin nRF51822

Dependents:   microbit-eddystone

Fork of microbit-dal by Lancaster University

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MicroBitIOPinService.cpp Source File

MicroBitIOPinService.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 the custom MicroBit IOPin Service.
00028   * Provides a BLE service to remotely read the state of the I/O Pin, and configure its behaviour.
00029   */
00030 #include "MicroBitConfig.h"
00031 #include "ble/UUID.h"
00032 
00033 #include "MicroBitIOPinService.h"
00034 #include "MicroBitFiber.h"
00035 
00036 /**
00037   * Constructor.
00038   * Create a representation of the IOPinService
00039   * @param _ble The instance of a BLE device that we're running on.
00040   * @param _io An instance of MicroBitIO that this service will use to perform
00041   *            I/O operations.
00042   */
00043 MicroBitIOPinService::MicroBitIOPinService(BLEDevice &_ble, MicroBitIO &_io) :
00044         ble(_ble), io(_io)
00045 {
00046     // Create the AD characteristic, that defines whether each pin is treated as analogue or digital
00047     GattCharacteristic ioPinServiceADCharacteristic(MicroBitIOPinServiceADConfigurationUUID, (uint8_t *)&ioPinServiceADCharacteristicBuffer, 0, sizeof(ioPinServiceADCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
00048 
00049     // Create the IO characteristic, that defines whether each pin is treated as input or output
00050     GattCharacteristic ioPinServiceIOCharacteristic(MicroBitIOPinServiceIOConfigurationUUID, (uint8_t *)&ioPinServiceIOCharacteristicBuffer, 0, sizeof(ioPinServiceIOCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE);
00051 
00052     // Create the Data characteristic, that allows the actual read and write operations.
00053     ioPinServiceDataCharacteristic = new GattCharacteristic(MicroBitIOPinServiceDataUUID, (uint8_t *)ioPinServiceDataCharacteristicBuffer, 0, sizeof(ioPinServiceDataCharacteristicBuffer), GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_NOTIFY);
00054 
00055     ioPinServiceDataCharacteristic->setReadAuthorizationCallback(this, &MicroBitIOPinService::onDataRead);
00056 
00057     ioPinServiceADCharacteristicBuffer = 0;
00058     ioPinServiceIOCharacteristicBuffer = 0;
00059     memset(ioPinServiceIOData, 0, sizeof(ioPinServiceIOData));
00060 
00061     // Set default security requirements
00062     ioPinServiceADCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
00063     ioPinServiceIOCharacteristic.requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
00064     ioPinServiceDataCharacteristic->requireSecurity(SecurityManager::MICROBIT_BLE_SECURITY_LEVEL);
00065 
00066     GattCharacteristic *characteristics[] = {&ioPinServiceADCharacteristic, &ioPinServiceIOCharacteristic, ioPinServiceDataCharacteristic};
00067     GattService         service(MicroBitIOPinServiceUUID, characteristics, sizeof(characteristics) / sizeof(GattCharacteristic *));
00068 
00069     ble.addService(service);
00070 
00071     ioPinServiceADCharacteristicHandle = ioPinServiceADCharacteristic.getValueHandle();
00072     ioPinServiceIOCharacteristicHandle = ioPinServiceIOCharacteristic.getValueHandle();
00073 
00074     ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer));
00075     ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
00076 
00077     ble.onDataWritten(this, &MicroBitIOPinService::onDataWritten);
00078     fiber_add_idle_component(this);
00079 }
00080 
00081 /**
00082   * Determines if the given pin was configured as a digital pin by the BLE ADPinConfigurationCharacterisitic.
00083   *
00084   * @param i the enumeration of the pin to test
00085   * @return 1 if this pin is configured as digital, 0 otherwise
00086   */
00087 int MicroBitIOPinService::isDigital(int i)
00088 {
00089     return ((ioPinServiceADCharacteristicBuffer & (1 << i)) == 0);
00090 }
00091 
00092 /**
00093   * Determines if the given pin was configured as an analog pin by the BLE ADPinConfigurationCharacterisitic.
00094   *
00095   * @param i the enumeration of the pin to test
00096   * @return 1 if this pin is configured as analog, 0 otherwise
00097   */
00098 int MicroBitIOPinService::isAnalog(int i)
00099 {
00100     return ((ioPinServiceADCharacteristicBuffer & (1 << i)) != 0);
00101 }
00102 
00103 /**
00104   * Determines if the given pin was configured as an input by the BLE IOPinConfigurationCharacterisitic.
00105   *
00106   * @param i the enumeration of the pin to test
00107   * @return 1 if this pin is configured as an input, 0 otherwise
00108   */
00109 int MicroBitIOPinService::isInput(int i)
00110 {
00111     return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) != 0);
00112 }
00113 
00114 /**
00115   * Determines if the given pin was configured as output by the BLE IOPinConfigurationCharacterisitic.
00116   *
00117   * @param i the enumeration of the pin to test
00118   * @return 1 if this pin is configured as an output, 0 otherwise
00119   */
00120 int MicroBitIOPinService::isOutput(int i)
00121 {
00122     return ((ioPinServiceIOCharacteristicBuffer & (1 << i)) == 0);
00123 }
00124 
00125 /**
00126   * Callback. Invoked when any of our attributes are written via BLE.
00127   */
00128 void MicroBitIOPinService::onDataWritten(const GattWriteCallbackParams *params)
00129 {
00130     // Check for writes to the IO configuration characteristic
00131     if (params->handle == ioPinServiceIOCharacteristicHandle && params->len >= sizeof(ioPinServiceIOCharacteristicBuffer))
00132     {
00133         uint32_t *value = (uint32_t *)params->data;
00134 
00135         // Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
00136         ioPinServiceIOCharacteristicBuffer = *value;
00137         ble.gattServer().write(ioPinServiceIOCharacteristicHandle, (const uint8_t *)&ioPinServiceIOCharacteristicBuffer, sizeof(ioPinServiceIOCharacteristicBuffer));
00138 
00139         // Also, drop any selected pins into input mode, so we can pick up changes later
00140         for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
00141         {
00142             if(isDigital(i) && isInput(i))
00143                io.pin[i].getDigitalValue();
00144                //MicroBitIOPins[i]->getDigitalValue();
00145 
00146             if(isAnalog(i) && isInput(i))
00147                io.pin[i].getAnalogValue();
00148                //MicroBitIOPins[i]->getAnalogValue();
00149         }
00150     }
00151 
00152     // Check for writes to the IO configuration characteristic
00153     if (params->handle == ioPinServiceADCharacteristicHandle && params->len >= sizeof(ioPinServiceADCharacteristicBuffer))
00154     {
00155         uint32_t *value = (uint32_t *)params->data;
00156 
00157         // Our IO configuration may be changing... read the new value, and push it back into the BLE stack.
00158         ioPinServiceADCharacteristicBuffer = *value;
00159         ble.gattServer().write(ioPinServiceADCharacteristicHandle, (const uint8_t *)&ioPinServiceADCharacteristicBuffer, sizeof(ioPinServiceADCharacteristicBuffer));
00160 
00161         // Also, drop any selected pins into input mode, so we can pick up changes later
00162         for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
00163         {
00164             if(isDigital(i) && isInput(i))
00165                io.pin[i].getDigitalValue();
00166                //MicroBitIOPins[i]->getDigitalValue();
00167 
00168             if(isAnalog(i) && isInput(i))
00169                io.pin[i].getAnalogValue();
00170                //MicroBitIOPins[i]->getAnalogValue();
00171         }
00172     }
00173 
00174     if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
00175     {
00176         // We have some pin data to change...
00177         uint16_t len = params->len;
00178         IOData *data = (IOData *)params->data;
00179 
00180         // There may be multiple write operaitons... take each in turn and update the pin values
00181         while (len >= sizeof(IOData))
00182         {
00183             if (isOutput(data->pin))
00184             {
00185                 if (isDigital(data->pin))
00186                     io.pin[data->pin].setDigitalValue(data->value);
00187                     //MicroBitIOPins[data->pin]->setDigitalValue(data->value);
00188                 else
00189                     io.pin[data->pin].setAnalogValue(data->value*4);
00190                     //MicroBitIOPins[data->pin]->setAnalogValue(data->value*4);
00191             }
00192 
00193             data++;
00194             len -= sizeof(IOData);
00195         }
00196     }
00197 }
00198 
00199 /**
00200  * Callback. invoked when the BLE data characteristic is read.
00201  *
00202  * Reads all the pins marked as inputs, and updates the data stored in the characteristic.
00203  */
00204 void MicroBitIOPinService::onDataRead(GattReadAuthCallbackParams *params)
00205 {
00206     if (params->handle == ioPinServiceDataCharacteristic->getValueHandle())
00207     {
00208 
00209         // Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
00210         int pairs = 0;
00211 
00212         for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
00213         {
00214             if (isInput(i))
00215             {
00216                 uint8_t value;
00217 
00218                 if (isDigital(i))
00219                     value = io.pin[i].getDigitalValue();
00220                     //value = MicroBitIOPins[i]->getDigitalValue();
00221                 else
00222                     value = io.pin[i].getAnalogValue();
00223                     //value = MicroBitIOPins[i]->getAnalogValue();
00224 
00225                 ioPinServiceIOData[i] = value;
00226                 ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
00227                 ioPinServiceDataCharacteristicBuffer[pairs].value = value;
00228 
00229                 pairs++;
00230 
00231                 if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
00232                     break;
00233             }
00234         }
00235 
00236         // If there's any data, issue a BLE notification.
00237         if (pairs > 0)
00238             ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
00239     }
00240 }
00241 
00242 
00243 /**
00244  * Periodic callback from MicroBit scheduler.
00245  *
00246  * Check if any of the pins we're watching need updating. Notify any connected
00247  * device with any changes.
00248  */
00249 void MicroBitIOPinService::idleTick()
00250 {
00251     // If we're not we're connected, then there's nothing to do...
00252     if (!ble.getGapState().connected)
00253         return;
00254 
00255     // Scan through all pins that our BLE client may be listening for. If any have changed value, update the BLE characterisitc, and NOTIFY our client.
00256     int pairs = 0;
00257 
00258     for (int i=0; i < MICROBIT_IO_PIN_SERVICE_PINCOUNT; i++)
00259     {
00260         if (isInput(i))
00261         {
00262             uint8_t value;
00263 
00264             if (isDigital(i))
00265                 value = io.pin[i].getDigitalValue();
00266                 //value = MicroBitIOPins[i]->getDigitalValue();
00267             else
00268                 value = io.pin[i].getAnalogValue();
00269                 //value = MicroBitIOPins[i]->getAnalogValue();
00270 
00271             // If the data has changed, send an update.
00272             if (value != ioPinServiceIOData[i])
00273             {
00274                 ioPinServiceIOData[i] = value;
00275 
00276                 ioPinServiceDataCharacteristicBuffer[pairs].pin = i;
00277                 ioPinServiceDataCharacteristicBuffer[pairs].value = value;
00278 
00279                 pairs++;
00280 
00281                 if (pairs >= MICROBIT_IO_PIN_SERVICE_DATA_SIZE)
00282                     break;
00283             }
00284         }
00285     }
00286 
00287     // If there were any changes, issue a BLE notification.
00288     if (pairs > 0)
00289         ble.gattServer().notify(ioPinServiceDataCharacteristic->getValueHandle(), (uint8_t *)ioPinServiceDataCharacteristicBuffer, pairs * sizeof(IOData));
00290 }
00291 
00292 const uint8_t  MicroBitIOPinServiceUUID[] = {
00293     0xe9,0x5d,0x12,0x7b,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
00294 };
00295 
00296 const uint8_t  MicroBitIOPinServiceIOConfigurationUUID[] = {
00297     0xe9,0x5d,0xb9,0xfe,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
00298 };
00299 
00300 const uint8_t  MicroBitIOPinServiceADConfigurationUUID[] = {
00301     0xe9,0x5d,0x58,0x99,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
00302 };
00303 
00304 const uint8_t MicroBitIOPinServiceDataUUID[] = {
00305     0xe9,0x5d,0x8d,0x00,0x25,0x1d,0x47,0x0a,0xa0,0x62,0xfa,0x19,0x22,0xdf,0xa9,0xa8
00306 };
00307 
00308 /*
00309 MicroBitPin * const MicroBitIOPins[] = {
00310     &uBit.io.P0,
00311     &uBit.io.P1,
00312     &uBit.io.P2,
00313     &uBit.io.P3,
00314     &uBit.io.P4,
00315     &uBit.io.P5,
00316     &uBit.io.P6,
00317     &uBit.io.P7,
00318     &uBit.io.P8,
00319     &uBit.io.P9,
00320     &uBit.io.P10,
00321     &uBit.io.P11,
00322     &uBit.io.P12,
00323     &uBit.io.P13,
00324     &uBit.io.P14,
00325     &uBit.io.P15,
00326     &uBit.io.P16,
00327     &uBit.io.P19,
00328     &uBit.io.P20
00329 };
00330 */