<!-- iframe showing the search results (closed by default) -->
<divid="MSearchResultsWindow">
<iframesrc="javascript:void(0)"frameborder="0"
name="MSearchResults" id="MSearchResults">
</iframe>
</div>
<divclass="PageDoc"><divclass="header">
<divclass="headertitle">
<divclass="title">Migrating from Bluedroid to NimBLE </div></div>
</div><!--header-->
<divclass="contents">
<divclass="textblock"><p>This guide describes the required changes to existing projects migrating from the original bluedroid API to NimBLE. <br/>
</p>
<p><b>The changes listed here are only the required changes that must be made</b>, and a short overview of options for migrating existing applications. <br/>
<p>For more information on the improvements and additions please refer to the <ahref="https://h2zero.github.io/esp-nimble-cpp/annotated.html">class documentation</a> and <aclass="el"href="md__improvements_and_updates.html">Improvements and updates</a><br/>
<p>All classes are accessible by including <code><aclass="el"href="_nim_b_l_e_device_8h_source.html">NimBLEDevice.h</a></code> in your application, no further headers need to be included. <br/>
</p>
<p>(Mainly for Arduino) You may choose to include <code><aclass="el"href="_nim_b_l_e_log_8h_source.html">NimBLELog.h</a></code> in your appplication if you want to use the <code>NIMBLE_LOGx</code> macros for debugging. <br/>
These macros are used the same way as the <code>ESP_LOGx</code> macros. <br/>
<p>Class names remain the same as the original with the addition of a "Nim" prefix. <br/>
For example <code>BLEDevice</code> is now <code><aclass="el"href="class_nim_b_l_e_device.html"title="A model of a BLE Device from which all the BLE roles are created.">NimBLEDevice</a></code> and <code>BLEServer</code> is now <code><aclass="el"href="class_nim_b_l_e_server.html"title="The model of a BLE server.">NimBLEServer</a></code> etc. <br/>
</p>
<p>For convienience definitions have been added to allow applications to use either name for all classes <br/>
this means <b>no class names need to be changed in existing code</b> and makes migrating easier. <br/>
<p><code>BLEAddress</code> (<code><aclass="el"href="class_nim_b_l_e_address.html"title="A BLE device address.">NimBLEAddress</a></code>) When constructing an address the constructor now takes an *(optional)* <code>uint8_t type</code> paramameter <br/>
to specify the address type. Default is (0) Public static address. <br/>
</p>
<p>For example <code>BLEAddress addr(11:22:33:44:55:66, 1)</code> will create the address object with an address type of: 1 (Random). <br/>
</p>
<p>As this paramameter is optional no changes to existing code are needed, it is mentioned here for information. <br/>
<br/>
<code>BLEAddress::getNative</code> (<code><aclass="el"href="class_nim_b_l_e_address.html#adef69a03a08303957d7e40eef07b4d80"title="Get the native representation of the address.">NimBLEAddress::getNative</a></code>) returns a uint8_t pointer to the native address byte array. <br/>
In this library the address bytes are stored in reverse order from the original library. This is due to the way <br/>
the NimBLE stack expects addresses to be presented to it. All other functions such as <code>toString</code> are <br/>
not affected as the endian change is made within them. <br/>
<p>Creating a <code>BLEServer</code> instance is the same as original, no changes required. For example <code>BLEDevice::createServer()</code> will work just as it did before. <br/>
</p>
<p><code>BLEServerCallbacks</code> (<code><aclass="el"href="class_nim_b_l_e_server_callbacks.html"title="Callbacks associated with the operation of a BLE server.">NimBLEServerCallbacks</a></code>) has new methods for handling security operations. <br/>
<b>Note:</b> All callback methods have default implementations which allows the application to implement only the methods applicable. <br/>
<p>Creating a <code>BLEService</code> (<code><aclass="el"href="class_nim_b_l_e_service.html"title="The model of a BLE service.">NimBLEService</a></code>) instance is the same as original, no changes required. <br/>
For example <code>BLEServer::createService(SERVICE_UUID)</code> will work just as it did before. <br/>
<p><code>BLEService::createCharacteristic</code> (<code><aclass="el"href="class_nim_b_l_e_service.html#adab5552c080b9cb88095af262d326309"title="Create a new BLE Characteristic associated with this service.">NimBLEService::createCharacteristic</a></code>) is used the same way as originally except the properties parameter has changed. <br/>
</p>
<p>When creating a characteristic the properties are now set with <code>NIMBLE_PROPERTY::XXXX</code> instead of <code>BLECharacteristic::XXXX</code>.</p>
</div><!-- fragment --><p> Needs to be changed to: </p><divclass="fragment"><divclass="line">BLECharacteristic *pCharacteristic = pService->createCharacteristic(</div>
<divclass="line"> CHARACTERISTIC_UUID,</div>
<divclass="line"> NIMBLE_PROPERTY::READ |</div>
<divclass="line"> NIMBLE_PROPERTY::WRITE </div>
<divclass="line"> );</div>
</div><!-- fragment --><p><br/>
</p>
<p><code>BLECharacteristicCallbacks</code> (<code><aclass="el"href="class_nim_b_l_e_characteristic_callbacks.html"title="Callbacks that can be associated with a BLE characteristic to inform of events.">NimBLECharacteristicCallbacks</a></code>) has a new method <code><aclass="el"href="class_nim_b_l_e_characteristic_callbacks.html#a3c0c0f524bc0d00d24a7c5ea92c5cb7e"title="Callback function called when a client changes subscription status.">NimBLECharacteristicCallbacks::onSubscribe</a></code><br/>
which is called when a client subscribes to notifications/indications. <br/>
</p>
<p><b>Note:</b> All callback methods have default implementations which allows the application to implement only the methods applicable. <br/>
<br/>
</p>
<blockquoteclass="doxtable">
<p>BLECharacteristic::getData <br/>
</p>
</blockquote>
<p><b>Has been removed from the API.</b><br/>
Originally this returned a <code>uint8_t*</code> to the internal data, which is volatile. <br/>
To prevent possibly throwing exceptions this has been removed and <code><aclass="el"href="class_nim_b_l_e_characteristic.html#a37e908d114f6ad2b4bf19c7cc4db9c54"title="Retrieve the current value of the characteristic.">NimBLECharacteristic::getValue</a></code> should be used <br/>
to get a copy of the data first which can then safely be accessed via pointer. <br/>
</p>
<p><b>Example:</b></p><divclass="fragment"><divclass="line">std::string value = pCharacteristic->getValue();</div>
</div><!-- fragment --><p> Alternatively use the <code>getValue</code> template: </p><divclass="fragment"><divclass="line">my_struct_t myStruct = pChr->getValue<my_struct_t>();</div>
<p>The previous method <code>BLECharacteristic::addDescriptor()</code> has been removed. <br/>
</p>
<p>Descriptors are now created using the <code><aclass="el"href="class_nim_b_l_e_characteristic.html#aae014669e9ce1ad01520d68fe0cc0fda"title="Create a new BLE Descriptor associated with this characteristic.">NimBLECharacteristic::createDescriptor</a></code> method.</p>
<p>BLE2902 or NimBLE2902 class has been removed. <br/>
NimBLE automatically creates the 0x2902 descriptor if a characteristic has a notification or indication property assigned to it. <br/>
</p>
<p>It was no longer useful to have a class for the 0x2902 descriptor as a new callback <code><aclass="el"href="class_nim_b_l_e_characteristic_callbacks.html#a3c0c0f524bc0d00d24a7c5ea92c5cb7e"title="Callback function called when a client changes subscription status.">NimBLECharacteristicCallbacks::onSubscribe</a></code> was added <br/>
to handle callback functionality and the client subscription status is handled internally. <br/>
</p>
<p><b>Note:</b> Attempting to create a 0x2902 descriptor will trigger an assert to notify the error, allowing the creation of it would cause a fault in the NimBLE stack.</p>
<p>All other descriptors are now created just as characteristics are by using the <code><aclass="el"href="class_nim_b_l_e_characteristic.html#aae014669e9ce1ad01520d68fe0cc0fda"title="Create a new BLE Descriptor associated with this characteristic.">NimBLECharacteristic::createDescriptor</a></code> method (except 0x2904, see below). <br/>
Which are defined as: </p><divclass="fragment"><divclass="line">NimBLEDescriptor* createDescriptor(const char* uuid,</div>
</div><!-- fragment --><p> Would create a descriptor with the UUID 0xABCD, publicly readable but only writable if paired/bonded (encrypted) and has a max value length of 25 bytes. <br/>
<br/>
</p>
<p>For the 0x2904, there is a special class that is created when you call `createDescriptor("2904").</p>
<p>The pointer returned is of the base class <code><aclass="el"href="class_nim_b_l_e_descriptor.html"title="A model of a BLE descriptor.">NimBLEDescriptor</a></code> but the call will create the derived class of <code><aclass="el"href="class_nim_b_l_e2904.html"title="Descriptor for Characteristic Presentation Format.">NimBLE2904</a></code> so you must cast the returned pointer to <br/>
<code><aclass="el"href="class_nim_b_l_e2904.html"title="Descriptor for Characteristic Presentation Format.">NimBLE2904</a></code> to access the specific class methods.</p>
<p>Advertising works the same as the original API except: <br/>
</p><blockquoteclass="doxtable">
<p>BLEAdvertising::setMinPreferred <br/>
BLEAdvertising::setMaxPreferred <br/>
</p>
</blockquote>
<p>These methods were found to not provide useful functionality and consumed valuable advertising space (6 bytes of 31) if used unknowingly. <br/>
If you wish to advertise these parameters you can still do so manually via <code>BLEAdvertisementData::addData</code> (<code><aclass="el"href="class_nim_b_l_e_advertisement_data.html#aec5f567059c4b4fd0f6b5fc74a0ce870"title="Add data to the payload to be advertised.">NimBLEAdvertisementData::addData</a></code>). <br/>
<br/>
</p>
<p>Calling <code><aclass="el"href="class_nim_b_l_e_advertising.html#af7083f58717b7e76d90d367f00a0ef08"title="Set the advertisement data that is to be published in a regular advertisement.">NimBLEAdvertising::setAdvertisementData</a></code> will entirely replace any data set with <code><aclass="el"href="class_nim_b_l_e_advertising.html#a4f334752ea04223185292fe9ab524b69"title="Add a service uuid to exposed list of services.">NimBLEAdvertising::addServiceUUID</a></code>, or <br/>
<code><aclass="el"href="class_nim_b_l_e_advertising.html#aa0d30dfb57670cc8180e17dffddad416"title="Set the device appearance in the advertising data. The codes for distinct appearances can be found he...">NimBLEAdvertising::setAppearance</a></code> or similar methods. You should set all the data you wish to advertise within the <code><aclass="el"href="class_nim_b_l_e_advertisement_data.html"title="Advertisement data set by the programmer to be published by the BLE server.">NimBLEAdvertisementData</a></code> instead. <br/>
</p>
<p><strike>Calling <code><aclass="el"href="class_nim_b_l_e_advertising.html#a04a51a0c639a70295a9b671f73b34358"title="Set the advertisement data that is to be published in a scan response.">NimBLEAdvertising::setScanResponseData</a></code> without also calling <code><aclass="el"href="class_nim_b_l_e_advertising.html#af7083f58717b7e76d90d367f00a0ef08"title="Set the advertisement data that is to be published in a regular advertisement.">NimBLEAdvertising::setAdvertisementData</a></code> will have no effect. <br/>
When using custom scan response data you must also use custom advertisement data.</strike><br/>
No longer true as of release 1.2.0 and above, custom scan response is now supported without custom advertisement data. <br/>
<p>Now takes 2 optional parameters, the first is the duration to advertise for (in seconds), the second is a callback <br/>
that is invoked when advertsing ends and takes a pointer to a <code><aclass="el"href="class_nim_b_l_e_advertising.html"title="Perform and manage BLE advertising.">NimBLEAdvertising</a></code> object (similar to the <code><aclass="el"href="class_nim_b_l_e_scan.html#a21b1e27816717b77533755f31dfaa820"title="Start scanning.">NimBLEScan::start</a></code> API). <br/>
</p>
<p>This provides an opportunity to update the advertisment data if desired. <br/>
<p>Client instances are created just as before with <code>BLEDevice::createClient</code> (<code><aclass="el"href="class_nim_b_l_e_device.html#af8142995252f486916dbb9de2a5b0c9e"title="Creates a new client object and maintains a list of all client objects each client can connect to 1 p...">NimBLEDevice::createClient</a></code>). <br/>
</p>
<p>Multiple client instances can be created, up to the maximum number of connections set in the config file (default: 3). <br/>
To delete a client instance you must use <code><aclass="el"href="class_nim_b_l_e_device.html#a83aa0a3d9d57358d35082a442edf8549"title="Delete the client object and remove it from the list. Checks if it is connected or trying to connect ...">NimBLEDevice::deleteClient</a></code>. <br/>
</p>
<p><code>BLEClient::connect</code>(<code><aclass="el"href="class_nim_b_l_e_client.html#aab311f0a8af21fb63f78e7fbac29951a"title="Connect to an advertising device.">NimBLEClient::connect</a></code>) Has had it's parameters altered. <br/>
Defined as: </p><blockquoteclass="doxtable">
<p><aclass="el"href="class_nim_b_l_e_client.html#aab311f0a8af21fb63f78e7fbac29951a"title="Connect to an advertising device.">NimBLEClient::connect</a>(bool deleteServices = true); <br/>
<aclass="el"href="class_nim_b_l_e_client.html#aab311f0a8af21fb63f78e7fbac29951a"title="Connect to an advertising device.">NimBLEClient::connect</a>(NimBLEAdvertisedDevice* device, bool deleteServices = true); <br/>
<aclass="el"href="class_nim_b_l_e_client.html#aab311f0a8af21fb63f78e7fbac29951a"title="Connect to an advertising device.">NimBLEClient::connect</a>(<aclass="el"href="class_nim_b_l_e_address.html"title="A BLE device address.">NimBLEAddress</a> address, bool deleteServices = true); <br/>
</p>
</blockquote>
<p>The type parameter has been removed and a new bool parameter has been added to indicate if the client should <br/>
delete the attribute database previously retrieved (if applicable) for the peripheral, default value is true. <br/>
If set to false the client will use the attribute database it retrieved from the peripheral when previously connected. <br/>
This allows for faster connections and power saving if the devices dropped connection and are reconnecting. <br/>
<br/>
</p>
<blockquoteclass="doxtable">
<p><code>BLEClient::getServices</code> (<code><aclass="el"href="class_nim_b_l_e_client.html#acb9007569b3bb13b3b49f3c4cb47b21a"title="Get a pointer to the vector of found services.">NimBLEClient::getServices</a></code>) <br/>
</p>
</blockquote>
<p>This method now takes an optional (bool) parameter to indicate if the services should be retrieved from the server (true) or <br/>
the currently known database returned (false : default). <br/>
Also now returns a pointer to <code>std::vector</code> instead of <code>std::map</code>. <br/>
<br/>
</p>
<p><b>Removed:</b> the automatic discovery of all peripheral attributes as they consumed time and resources for data <br/>
the user may not be interested in. <br/>
</p>
<p><b>Added:</b><code><aclass="el"href="class_nim_b_l_e_client.html#a3d8cbf51caf8b3b8a0ec6ce2074ba71d"title="Retrieves the full database of attributes that the peripheral has available.">NimBLEClient::discoverAttributes</a></code> for the user to discover all the peripheral attributes <br/>
to replace the the removed automatic functionality. <br/>
<p><code>BLERemoteService</code> (<code><aclass="el"href="class_nim_b_l_e_remote_service.html"title="A model of a remote BLE service.">NimBLERemoteService</a></code>) Methods remain mostly unchanged with the exceptions of: <br/>
<p><code>BLERemoteService::getCharacteristics</code> (<code><aclass="el"href="class_nim_b_l_e_remote_service.html#a2c9e91c842598a6a9576c7b87af0863a"title="Get a pointer to the vector of found characteristics.">NimBLERemoteService::getCharacteristics</a></code>) </p>
</blockquote>
<p>This method now takes an optional (bool) parameter to indicate if the characteristics should be retrieved from the server (true) or <br/>
the currently known database returned (false : default). <br/>
Also now returns a pointer to <code>std::vector</code> instead of <code>std::map</code>. <br/>
<p><code>BLERemoteCharacteristic</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html"title="A model of a remote BLE characteristic.">NimBLERemoteCharacteristic</a></code>) There have been a few changes to the methods in this class: <br/>
</p>
<blockquoteclass="doxtable">
<p><code>BLERemoteCharacteristic::writeValue</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#a3c8d1fd77dd074df866c091c614eafb3"title="Write the new value for the characteristic from a data buffer.">NimBLERemoteCharacteristic::writeValue</a></code>) <br/>
<code>BLERemoteCharacteristic::registerForNotify</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#ab4f54eabe90a416546b7b3fc3477f49c"title="backward-compatibility method for subscribe/unsubscribe notifications/indications">NimBLERemoteCharacteristic::registerForNotify</a></code>) <br/>
</p>
</blockquote>
<p>Now return true or false to indicate success or failure so you can choose to disconnect or try again. <br/>
<br/>
</p>
<blockquoteclass="doxtable">
<p><code>BLERemoteCharacteristic::registerForNotify</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#ab4f54eabe90a416546b7b3fc3477f49c"title="backward-compatibility method for subscribe/unsubscribe notifications/indications">NimBLERemoteCharacteristic::registerForNotify</a></code>) <br/>
</p>
</blockquote>
<p>Is now <b>deprecated</b>. <br/>
</p><blockquoteclass="doxtable">
<p><code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#aa08b2f62376568e1fc833e4ff91e8aa7"title="Subscribe for notifications or indications.">NimBLERemoteCharacteristic::subscribe</a></code><br/>
<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#a6e331afdbdbc32bf461c9866236a97aa"title="Unsubscribe for notifications or indications.">NimBLERemoteCharacteristic::unsubscribe</a></code><br/>
</p>
</blockquote>
<p>Are the new methods added to replace it. <br/>
<br/>
</p>
<blockquoteclass="doxtable">
<p><code>BLERemoteCharacteristic::readUInt8</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#ade5c6ae280c3cf36c9905be23df8f080"title="Read a byte value.">NimBLERemoteCharacteristic::readUInt8</a></code>) <br/>
<code>BLERemoteCharacteristic::readUInt16</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#a181c54862bc422d8ad0b326af675922d"title="Read an unsigned 16 bit value.">NimBLERemoteCharacteristic::readUInt16</a></code>) <br/>
<code>BLERemoteCharacteristic::readUInt32</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#a71793454ffab034f87af3a5e9677a63d"title="Read an unsigned 32 bit value.">NimBLERemoteCharacteristic::readUInt32</a></code>) <br/>
<code>BLERemoteCharacteristic::readFloat</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#a81f39759d48a8fb792c94e4b3b455eef"title="Read a float value.">NimBLERemoteCharacteristic::readFloat</a></code>) <br/>
</p>
</blockquote>
<p>Are <b>deprecated</b> a template: <aclass="el"href="class_nim_b_l_e_remote_characteristic.html#a7e10fa37095d7c80dc36c768fe783e67"title="Read the value of the remote characteristic.">NimBLERemoteCharacteristic::readValue</a><type>(time_t*, bool) has been added to replace them. <br/>
Originally it stored an unnecessary copy of the data and was returning a <code>uint8_t</code> pointer to volatile internal data. <br/>
The user application should use <code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#a7e10fa37095d7c80dc36c768fe783e67"title="Read the value of the remote characteristic.">NimBLERemoteCharacteristic::readValue</a></code> or <code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#add1a1daed14b5f3e729e284dbd369257"title="Get the value of the remote characteristic.">NimBLERemoteCharacteristic::getValue</a></code>. <br/>
To obatain a copy of the data, then cast the returned std::string to the type required such as: <br/>
</p><divclass="fragment"><divclass="line">std::string value = pChr->readValue();</div>
</div><!-- fragment --><p> Alternatively use the <code>readValue</code> template: </p><divclass="fragment"><divclass="line">my_struct_t myStruct = pChr->readValue<my_struct_t>();</div>
</div><!-- fragment --><p><br/>
</p>
<blockquoteclass="doxtable">
<p><code>BLERemoteCharacteristic::getDescriptors</code> (<code><aclass="el"href="class_nim_b_l_e_remote_characteristic.html#acf11d225fe5a25327742349e9d6061f9"title="Get a pointer to the vector of found descriptors.">NimBLERemoteCharacteristic::getDescriptors</a></code>) <br/>
</p>
</blockquote>
<p>This method now takes an optional (bool) parameter to indicate if the descriptors should be retrieved from the server (true) or <br/>
the currently known database returned (false : default). <br/>
Also now returns a pointer to <code>std::vector</code> instead of <code>std::map</code>. <br/>
<p>Security operations have been moved to <code>BLEDevice</code> (<code><aclass="el"href="class_nim_b_l_e_device.html"title="A model of a BLE Device from which all the BLE roles are created.">NimBLEDevice</a></code>).</p>
<p>Also security callback methods are now incorporated in the <code><aclass="el"href="class_nim_b_l_e_server_callbacks.html"title="Callbacks associated with the operation of a BLE server.">NimBLEServerCallbacks</a></code> / <code><aclass="el"href="class_nim_b_l_e_client_callbacks.html"title="Callbacks associated with a BLE client.">NimBLEClientCallbacks</a></code> classes. <br/>
However backward compatibility with the original <code>BLESecurity</code> (<code><aclass="el"href="class_nim_b_l_e_security.html"title="A class to handle BLE security operations. Deprecated - provided for backward compatibility only.">NimBLESecurity</a></code>) class is retained to minimize application code changes. <br/>
<p>Authentication complete, success or failed information is in <code>desc</code>. <br/>
<br/>
</p>
<p>Security settings and IO capabilities are now set by the following methods of <aclass="el"href="class_nim_b_l_e_device.html"title="A model of a BLE Device from which all the BLE roles are created.">NimBLEDevice</a>. </p><blockquoteclass="doxtable">
<p><code><aclass="el"href="class_nim_b_l_e_device.html#aa8e340c02418771ce72dec758d560938"title="Set the authorization mode for this device.">NimBLEDevice::setSecurityAuth(bool bonding, bool mitm, bool sc)</a></code><br/>
<code><aclass="el"href="class_nim_b_l_e_device.html#a2f10da171794581870d678fc947a5d1f"title="Set the authorization mode for this device.">NimBLEDevice::setSecurityAuth(uint8_t auth_req)</a></code><br/>
</p>
</blockquote>
<p>Sets the authorization mode for this device. <br/>
<br/>
</p>
<blockquoteclass="doxtable">
<p><code><aclass="el"href="class_nim_b_l_e_device.html#ab9fee9e810d5fa18bc8a37053eb9b5d0"title="Set the Input/Output capabilities of this device.">NimBLEDevice::setSecurityIOCap(uint8_t iocap)</a></code><br/>
</p>
</blockquote>
<p>Sets the Input/Output capabilities of this device. <br/>
<br/>
</p>
<blockquoteclass="doxtable">
<p><code><aclass="el"href="class_nim_b_l_e_device.html#a92d36c3a34d9474fa1d7f66c0e477d1e"title="If we are the initiator of the security procedure this sets the keys we will distribute.">NimBLEDevice::setSecurityInitKey(uint8_t init_key)</a></code><br/>
</p>
</blockquote>
<p>If we are the initiator of the security procedure this sets the keys we will distribute. <br/>
<br/>
</p>
<blockquoteclass="doxtable">
<p><code><aclass="el"href="class_nim_b_l_e_device.html#a57f0d4db1cc564176b23e860fce13f6a"title="Set the keys we are willing to accept during pairing.">NimBLEDevice::setSecurityRespKey(uint8_t resp_key)</a></code><br/>
</p>
</blockquote>
<p>Sets the keys we are willing to accept from the peer during pairing. <br/>
<liclass="footer">Generated by <ahref="https://www.doxygen.org/index.html"><imgclass="footer"src="doxygen.svg"width="104"height="31"alt="doxygen"/></a> 1.9.1 </li>