my version with changed conversion between duration units

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