Minor temporary patch to allow DFU packet callback

Fork of BLE_API by Bluetooth Low Energy

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers URIBeaconConfigService.h Source File

URIBeaconConfigService.h

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2006-2013 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #ifndef SERVICES_URIBEACONCONFIGSERVICE_H_
00018 #define SERVICES_URIBEACONCONFIGSERVICE_H_
00019 
00020 #include "BLEDevice.h"
00021 #include "mbed.h"
00022 
00023 #define UUID_URI_BEACON(FIRST, SECOND) {                         \
00024         0xee, 0x0c, FIRST, SECOND, 0x87, 0x86, 0x40, 0xba,       \
00025         0xab, 0x96, 0x99, 0xb9, 0x1a, 0xc9, 0x81, 0xd8,          \
00026 }
00027 
00028 static const uint8_t UUID_URI_BEACON_SERVICE[]    = UUID_URI_BEACON(0x20, 0x80);
00029 static const uint8_t UUID_LOCK_STATE_CHAR[]       = UUID_URI_BEACON(0x20, 0x81);
00030 static const uint8_t UUID_LOCK_CHAR[]             = UUID_URI_BEACON(0x20, 0x82);
00031 static const uint8_t UUID_UNLOCK_CHAR[]           = UUID_URI_BEACON(0x20, 0x83);
00032 static const uint8_t UUID_URI_DATA_CHAR[]         = UUID_URI_BEACON(0x20, 0x84);
00033 static const uint8_t UUID_FLAGS_CHAR[]            = UUID_URI_BEACON(0x20, 0x85);
00034 static const uint8_t UUID_ADV_POWER_LEVELS_CHAR[] = UUID_URI_BEACON(0x20, 0x86);
00035 static const uint8_t UUID_TX_POWER_MODE_CHAR[]    = UUID_URI_BEACON(0x20, 0x87);
00036 static const uint8_t UUID_BEACON_PERIOD_CHAR[]    = UUID_URI_BEACON(0x20, 0x88);
00037 static const uint8_t UUID_RESET_CHAR[]            = UUID_URI_BEACON(0x20, 0x89);
00038 static const uint8_t BEACON_UUID[] = {0xD8, 0xFE};
00039 
00040 /**
00041 * @class URIBeaconConfigService
00042 * @brief UriBeacon Configuration Service. Can be used to set URL, adjust power levels, and set flags.
00043 * See http://uribeacon.org
00044 *
00045 */
00046 class URIBeaconConfigService {
00047   public:
00048     /**
00049      * @brief Transmission Power Modes for UriBeacon
00050      */
00051     static const uint8_t TX_POWER_MODE_LOWEST = 0; /*!< Lowest TX power mode */
00052     static const uint8_t TX_POWER_MODE_LOW     = 1; /*!< Low TX power mode */
00053     static const uint8_t TX_POWER_MODE_MEDIUM  = 2; /*!< Medium TX power mode */
00054     static const uint8_t TX_POWER_MODE_HIGH    = 3; /*!< High TX power mode */
00055     static const unsigned int NUM_POWER_MODES  = 4; /*!< Number of Power Modes defined */
00056 
00057     static const int ADVERTISING_INTERVAL_MSEC = 1000;  // Advertising interval for config service.
00058     static const int SERVICE_DATA_MAX = 31;             // Maximum size of service data in ADV packets
00059 
00060     typedef uint8_t Lock_t[16];               /* 128 bits */
00061     typedef int8_t PowerLevels_t[NUM_POWER_MODES ];
00062 
00063     static const int URI_DATA_MAX = 18;
00064     typedef uint8_t  UriData_t[URI_DATA_MAX];
00065 
00066     struct Params_t {
00067         Lock_t        lock;
00068         uint8_t       uriDataLength;
00069         UriData_t     uriData;
00070         uint8_t       flags;
00071         PowerLevels_t advPowerLevels; // Current value of AdvertisedPowerLevels
00072         uint8_t       txPowerMode;    // Firmware power levels used with setTxPower()
00073         uint16_t      beaconPeriod;
00074     };
00075 
00076     /**
00077      * @param[ref]    ble
00078      *                    BLEDevice object for the underlying controller.
00079      * @param[in/out] paramsIn
00080      *                    Reference to application-visible beacon state, loaded
00081      *                    from persistent storage at startup.
00082      * @paramsP[in]   resetToDefaultsFlag
00083      *                    Applies to the state of the 'paramsIn' parameter.
00084      *                    If true, it indicates that paramsIn is potentially
00085      *                    un-initialized, and default values should be used
00086      *                    instead. Otherwise, paramsIn overrides the defaults.
00087      * @param[in]     defaultUriDataIn
00088      *                    Default un-encoded URI; applies only if the resetToDefaultsFlag is true.
00089      * @param[in]     defaultAdvPowerLevelsIn
00090      *                    Default power-levels array; applies only if the resetToDefaultsFlag is true.
00091      */
00092     URIBeaconConfigService (BLEDevice     &bleIn,
00093                            Params_t      &paramsIn,
00094                            bool          resetToDefaultsFlag,
00095                            const char   *defaultURIDataIn,
00096                            PowerLevels_t &defaultAdvPowerLevelsIn) :
00097         ble(bleIn),
00098         params(paramsIn),
00099         defaultUriDataLength(),
00100         defaultUriData(),
00101         defaultAdvPowerLevels(defaultAdvPowerLevelsIn),
00102         initSucceeded(false),
00103         resetFlag(),
00104         lockedStateChar(UUID_LOCK_STATE_CHAR, &lockedState),
00105         lockChar(UUID_LOCK_CHAR, &params.lock),
00106         uriDataChar(UUID_URI_DATA_CHAR, params.uriData, 0, URI_DATA_MAX,
00107                     GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_READ | GattCharacteristic::BLE_GATT_CHAR_PROPERTIES_WRITE),
00108         unlockChar(UUID_UNLOCK_CHAR, &params.lock),
00109         flagsChar(UUID_FLAGS_CHAR, &params.flags),
00110         advPowerLevelsChar(UUID_ADV_POWER_LEVELS_CHAR, &params.advPowerLevels),
00111         txPowerModeChar(UUID_TX_POWER_MODE_CHAR, &params.txPowerMode),
00112         beaconPeriodChar(UUID_BEACON_PERIOD_CHAR, &params.beaconPeriod),
00113         resetChar(UUID_RESET_CHAR, &resetFlag) {
00114 
00115         encodeURI(defaultURIDataIn, defaultUriData, defaultUriDataLength);
00116         if (defaultUriDataLength > URI_DATA_MAX) {
00117             return;
00118         }
00119 
00120         if (!resetToDefaultsFlag && (params.uriDataLength > URI_DATA_MAX)) {
00121             resetToDefaultsFlag = true;
00122         }
00123         if (resetToDefaultsFlag) {
00124             resetToDefaults();
00125         } else {
00126             updateCharacteristicValues();
00127         }
00128 
00129         lockedState = isLocked();
00130 
00131         lockChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::lockAuthorizationCallback);
00132         unlockChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::unlockAuthorizationCallback);
00133         uriDataChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::uriDataWriteAuthorizationCallback);
00134         flagsChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint8_t>);
00135         advPowerLevelsChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<PowerLevels_t>);
00136         txPowerModeChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::powerModeAuthorizationCallback);
00137         beaconPeriodChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint16_t>);
00138         resetChar.setWriteAuthorizationCallback(this, &URIBeaconConfigService::basicAuthorizationCallback<uint8_t>);
00139 
00140         static GattCharacteristic *charTable[] = {
00141             &lockedStateChar, &lockChar, &unlockChar, &uriDataChar,
00142             &flagsChar, &advPowerLevelsChar, &txPowerModeChar, &beaconPeriodChar, &resetChar
00143         };
00144 
00145         GattService configService(UUID_URI_BEACON_SERVICE, charTable, sizeof(charTable) / sizeof(GattCharacteristic *));
00146 
00147         ble.addService(configService);
00148         ble.onDataWritten(this, &URIBeaconConfigService::onDataWrittenCallback);
00149 
00150         setupURIBeaconConfigAdvertisements(); /* Setup advertising for the configService. */
00151 
00152         initSucceeded = true;
00153     }
00154 
00155     bool configuredSuccessfully(void) const {
00156         return initSucceeded;
00157     }
00158 
00159     /* Start out by advertising the configService for a limited time after
00160      * startup; and switch to the normal non-connectible beacon functionality
00161      * afterwards. */
00162     void setupURIBeaconConfigAdvertisements()
00163     {
00164         const char DEVICE_NAME[] = "mUriBeacon Config";
00165 
00166         ble.clearAdvertisingPayload();
00167 
00168         ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00169 
00170         // UUID is in different order in the ADV frame (!)
00171         uint8_t reversedServiceUUID[sizeof(UUID_URI_BEACON_SERVICE)];
00172         for (unsigned int i = 0; i < sizeof(UUID_URI_BEACON_SERVICE); i++) {
00173             reversedServiceUUID[i] = UUID_URI_BEACON_SERVICE[sizeof(UUID_URI_BEACON_SERVICE) - i - 1];
00174         }
00175         ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS, reversedServiceUUID, sizeof(reversedServiceUUID));
00176         ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_TAG);
00177         ble.accumulateScanResponse(GapAdvertisingData::COMPLETE_LOCAL_NAME, reinterpret_cast<const uint8_t *>(&DEVICE_NAME), sizeof(DEVICE_NAME));
00178         ble.accumulateScanResponse(
00179             GapAdvertisingData::TX_POWER_LEVEL,
00180             reinterpret_cast<uint8_t *>(&defaultAdvPowerLevels[URIBeaconConfigService::TX_POWER_MODE_LOW ]),
00181             sizeof(uint8_t));
00182 
00183         ble.setTxPower(params.advPowerLevels[params.txPowerMode]);
00184         ble.setDeviceName(reinterpret_cast<const uint8_t *>(&DEVICE_NAME));
00185         ble.setAdvertisingType (GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
00186         ble.setAdvertisingInterval (Gap::MSEC_TO_ADVERTISEMENT_DURATION_UNITS(ADVERTISING_INTERVAL_MSEC));
00187     }
00188 
00189     /* Helper function to switch to the non-connectible normal mode for URIBeacon. This gets called after a timeout. */
00190     void setupURIBeaconAdvertisements()
00191     {
00192         uint8_t serviceData[SERVICE_DATA_MAX];
00193         unsigned serviceDataLen = 0;
00194 
00195         /* Reinitialize the BLE stack. This will clear away the existing services and advertising state. */
00196         ble.shutdown();
00197         ble.init();
00198 
00199         // Fields from the Service
00200         unsigned beaconPeriod                                 = params.beaconPeriod;
00201         unsigned txPowerMode                                  = params.txPowerMode;
00202         unsigned uriDataLength                                = params.uriDataLength;
00203         URIBeaconConfigService::UriData_t &uriData            = params.uriData;
00204         URIBeaconConfigService::PowerLevels_t &advPowerLevels = params.advPowerLevels;
00205         uint8_t flags                                         = params.flags;
00206 
00207         extern void saveURIBeaconConfigParams(const Params_t *paramsP); /* forward declaration; necessary to avoid a circular dependency. */
00208         saveURIBeaconConfigParams(&params);
00209 
00210         ble.clearAdvertisingPayload();
00211         ble.setTxPower(params.advPowerLevels[params.txPowerMode]);
00212         ble.setAdvertisingType (GapAdvertisingParams::ADV_NON_CONNECTABLE_UNDIRECTED);
00213         ble.setAdvertisingInterval (beaconPeriod);
00214         ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
00215         ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, BEACON_UUID, sizeof(BEACON_UUID));
00216 
00217         serviceData[serviceDataLen++] = BEACON_UUID[0];
00218         serviceData[serviceDataLen++] = BEACON_UUID[1];
00219         serviceData[serviceDataLen++] = flags;
00220         serviceData[serviceDataLen++] = advPowerLevels[txPowerMode];
00221         for (unsigned j = 0; j < uriDataLength; j++) {
00222             serviceData[serviceDataLen++] = uriData[j];
00223         }
00224         ble.accumulateAdvertisingPayload(GapAdvertisingData::SERVICE_DATA, serviceData, serviceDataLen);
00225     }
00226 
00227   private:
00228     // True if the lock bits are non-zero
00229     bool isLocked() {
00230         Lock_t testLock;
00231         memset(testLock, 0, sizeof(Lock_t));
00232         return memcmp(params.lock, testLock, sizeof(Lock_t));
00233     }
00234 
00235     /*
00236      * This callback is invoked when a GATT client attempts to modify any of the
00237      * characteristics of this service. Attempts to do so are also applied to
00238      * the internal state of this service object.
00239      */
00240     void onDataWrittenCallback(const GattCharacteristicWriteCBParams *writeParams) {
00241         uint16_t handle = writeParams->charHandle;
00242 
00243         if (handle == lockChar.getValueHandle()) {
00244             // Validated earlier
00245             memcpy(params.lock, writeParams->data, sizeof(Lock_t));
00246             // use isLocked() in case bits are being set to all 0's
00247             lockedState = isLocked();
00248         } else if (handle == unlockChar.getValueHandle()) {
00249             // Validated earlier
00250             memset(params.lock, 0, sizeof(Lock_t));
00251             lockedState = false;
00252         } else if (handle == uriDataChar.getValueHandle()) {
00253             params.uriDataLength = writeParams->len;
00254             memcpy(params.uriData, writeParams->data, params.uriDataLength);
00255         } else if (handle == flagsChar.getValueHandle()) {
00256             params.flags = *(writeParams->data);
00257         } else if (handle == advPowerLevelsChar.getValueHandle()) {
00258             memcpy(params.advPowerLevels, writeParams->data, sizeof(PowerLevels_t));
00259         } else if (handle == txPowerModeChar.getValueHandle()) {
00260             params.txPowerMode = *(writeParams->data);
00261         } else if (handle == beaconPeriodChar.getValueHandle()) {
00262             params.beaconPeriod = *((uint16_t *)(writeParams->data));
00263         } else if (handle == resetChar.getValueHandle()) {
00264             resetToDefaults();
00265         }
00266     }
00267 
00268     /*
00269      * Reset the default values.
00270      */
00271     void resetToDefaults(void) {
00272         lockedState             = false;
00273         memset(params.lock, 0, sizeof(Lock_t));
00274         memcpy(params.uriData, defaultUriData, URI_DATA_MAX);
00275         params.uriDataLength    = defaultUriDataLength;
00276         params.flags            = 0;
00277         memcpy(params.advPowerLevels, defaultAdvPowerLevels, sizeof(PowerLevels_t));
00278         params.txPowerMode      = TX_POWER_MODE_LOW ;
00279         params.beaconPeriod     = 1000;
00280         updateCharacteristicValues();
00281     }
00282 
00283     /*
00284      * Internal helper function used to update the GATT database following any
00285      * change to the internal state of the service object.
00286      */
00287     void updateCharacteristicValues(void) {
00288         ble.updateCharacteristicValue (lockedStateChar.getValueHandle(), &lockedState, 1);
00289         ble.updateCharacteristicValue (uriDataChar.getValueHandle(), params.uriData, params.uriDataLength);
00290         ble.updateCharacteristicValue (flagsChar.getValueHandle(), &params.flags, 1);
00291         ble.updateCharacteristicValue (beaconPeriodChar.getValueHandle(),
00292                                       reinterpret_cast<uint8_t *>(&params.beaconPeriod), sizeof(uint16_t));
00293         ble.updateCharacteristicValue (txPowerModeChar.getValueHandle(), &params.txPowerMode, 1);
00294         ble.updateCharacteristicValue (advPowerLevelsChar.getValueHandle(),
00295                                       reinterpret_cast<uint8_t *>(params.advPowerLevels), sizeof(PowerLevels_t));
00296     }
00297 
00298   private:
00299     void lockAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
00300         if (lockedState) {
00301             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
00302         } else if (authParams->len != sizeof(Lock_t)) {
00303             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
00304         } else if (authParams->offset != 0) {
00305             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
00306         } else {
00307             authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
00308         }
00309     }
00310 
00311 
00312     void unlockAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
00313         if (!lockedState) {
00314             authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
00315         } else if (authParams->len != sizeof(Lock_t)) {
00316             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
00317         } else if (authParams->offset != 0) {
00318             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
00319         } else if (memcmp(authParams->data, params.lock, sizeof(Lock_t)) != 0) {
00320             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
00321         } else {
00322             authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
00323         }
00324     }
00325 
00326     void uriDataWriteAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
00327         if (lockedState) {
00328             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
00329         } else if (authParams->offset != 0) {
00330             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
00331         } else {
00332             authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
00333         }
00334     }
00335 
00336     void powerModeAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
00337         if (lockedState) {
00338             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
00339         } else if (authParams->len != sizeof(uint8_t)) {
00340             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
00341         } else if (authParams->offset != 0) {
00342             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
00343         } else if (*((uint8_t *)authParams->data) >= NUM_POWER_MODES ) {
00344             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_WRITE_NOT_PERMITTED;
00345         } else {
00346             authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
00347         }
00348     }
00349 
00350     template <typename T>
00351     void basicAuthorizationCallback(GattCharacteristicWriteAuthCBParams *authParams) {
00352         if (lockedState) {
00353             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INSUF_AUTHORIZATION;
00354         } else if (authParams->len != sizeof(T)) {
00355             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_ATT_VAL_LENGTH;
00356         } else if (authParams->offset != 0) {
00357             authParams->authorizationReply = AUTH_CALLBACK_REPLY_ATTERR_INVALID_OFFSET;
00358         } else {
00359             authParams->authorizationReply = AUTH_CALLBACK_REPLY_SUCCESS;
00360         }
00361     }
00362 
00363     BLEDevice     &ble;
00364     Params_t      &params;
00365     // Default value that is restored on reset
00366     size_t        defaultUriDataLength;
00367     UriData_t     defaultUriData;
00368     // Default value that is restored on reset
00369     PowerLevels_t &defaultAdvPowerLevels;
00370     uint8_t       lockedState;
00371     bool          initSucceeded;
00372     uint8_t       resetFlag;
00373 
00374     ReadOnlyGattCharacteristic<uint8_t>        lockedStateChar;
00375     WriteOnlyGattCharacteristic<Lock_t>        lockChar;
00376     GattCharacteristic                         uriDataChar;
00377     WriteOnlyGattCharacteristic<Lock_t>        unlockChar;
00378     ReadWriteGattCharacteristic<uint8_t>       flagsChar;
00379     ReadWriteGattCharacteristic<PowerLevels_t> advPowerLevelsChar;
00380     ReadWriteGattCharacteristic<uint8_t>       txPowerModeChar;
00381     ReadWriteGattCharacteristic<uint16_t>      beaconPeriodChar;
00382     WriteOnlyGattCharacteristic<uint8_t>       resetChar;
00383 
00384   public:
00385     /*
00386      *  Encode a human-readable URI into the binary format defined by URIBeacon spec (https://github.com/google/uribeacon/tree/master/specification).
00387      */
00388     static void encodeURI(const char *uriDataIn, UriData_t uriDataOut, size_t &sizeofURIDataOut) {
00389         const char *prefixes[] = {
00390             "http://www.",
00391             "https://www.",
00392             "http://",
00393             "https://",
00394             "urn:uuid:"
00395         };
00396         const size_t NUM_PREFIXES = sizeof(prefixes) / sizeof(char *);
00397         const char *suffixes[] = {
00398             ".com/",
00399             ".org/",
00400             ".edu/",
00401             ".net/",
00402             ".info/",
00403             ".biz/",
00404             ".gov/",
00405             ".com",
00406             ".org",
00407             ".edu",
00408             ".net",
00409             ".info",
00410             ".biz",
00411             ".gov"
00412         };
00413         const size_t NUM_SUFFIXES = sizeof(suffixes) / sizeof(char *);
00414 
00415         sizeofURIDataOut = 0;
00416         memset(uriDataOut, 0, sizeof(UriData_t));
00417 
00418         if ((uriDataIn == NULL) || (strlen(uriDataIn) == 0)) {
00419             return;
00420         }
00421 
00422         /*
00423          * handle prefix
00424          */
00425         for (unsigned i = 0; i < NUM_PREFIXES; i++) {
00426             size_t prefixLen = strlen(prefixes[i]);
00427             if (strncmp(uriDataIn, prefixes[i], prefixLen) == 0) {
00428                 uriDataOut[sizeofURIDataOut++]  = i;
00429                 uriDataIn                      += prefixLen;
00430                 break;
00431             }
00432         }
00433 
00434         /*
00435          * handle suffixes
00436          */
00437         while (*uriDataIn && (sizeofURIDataOut < URI_DATA_MAX)) {
00438             /* check for suffix match */
00439             unsigned i;
00440             for (i = 0; i < NUM_SUFFIXES; i++) {
00441                 size_t suffixLen = strlen(suffixes[i]);
00442                 if (strncmp(uriDataIn, suffixes[i], suffixLen) == 0) {
00443                     uriDataOut[sizeofURIDataOut++]  = i;
00444                     uriDataIn                      += suffixLen;
00445                     break; /* from the for loop for checking against suffixes */
00446                 }
00447             }
00448             /* This is the default case where we've got an ordinary character which doesn't match a suffix. */
00449             if (i == NUM_SUFFIXES) {
00450                 uriDataOut[sizeofURIDataOut++] = *uriDataIn;
00451                 ++uriDataIn;
00452             }
00453         }
00454     }
00455 };
00456 
00457 #endif  // SERVICES_URIBEACONCONFIGSERVICE_H_