this is using the mbed os version 5-13-1
Diff: source/BleManager.cpp
- Revision:
- 76:6afda865fbf8
- Parent:
- 75:08eff6258e1b
- Child:
- 77:0b505d1e15f4
--- a/source/BleManager.cpp Thu Mar 14 21:34:06 2019 +0000
+++ b/source/BleManager.cpp Fri Mar 15 14:26:44 2019 +0000
@@ -16,7 +16,9 @@
#include <events/mbed_events.h>
#include <mbed.h>
+#include "common_config.h"
#include "ble/BLE.h"
+#include "ble/services/UARTService.h"
#include "SecurityManager.h"
#include "BleManager.h"
#if MBED_CONF_APP_FILESYSTEM_SUPPORT
@@ -26,7 +28,9 @@
static const uint8_t DEVICE_NAME[] = "SM_device";
-
+//static const uint16_t uuid16_list[] = {LEDService::LED_SERVICE_UUID};
+extern UARTService *uart;
+extern char buffer[BUFFER_LEN];
/** This example demonstrates all the basic setup required
* for pairing and setting up link security both as a central and peripheral
*
@@ -142,11 +146,13 @@
printf("Link NOT_ENCRYPTED\r\n");
}
+#ifdef DEMO_BLE_SECURITY
/* disconnect in 2 s */
_event_queue.call_in(
2000, &_ble.gap(),
&Gap::disconnect, _handle, Gap::REMOTE_USER_TERMINATED_CONNECTION
);
+#endif
}
/** Override to start chosen activity when initialisation completes */
@@ -226,6 +232,7 @@
* attach callbacks that are used by Gap to notify us of events */
_ble.gap().onConnection(this, &SMDevice::on_connect);
_ble.gap().onDisconnection(this, &SMDevice::on_disconnect);
+ _ble.gattServer().onDataWritten(this, &SMDevice::onDataWrittenCallback);
/* start test in 500 ms */
_event_queue.call_in(500, this, &SMDevice::start);
@@ -256,6 +263,46 @@
_event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
};
+/** Echo received data back */
+void SMDevice::EchoBleUartReceived()
+{
+ uart->writeString(buffer);
+ uart->writeString("\n"); //flushes uart output buffer and sends data
+}
+
+
+/**
+ * This callback allows the LEDService to receive updates to the ledState Characteristic.
+ *
+ * @param[in] params
+ * Information about the characterisitc being updated.
+ */
+void SMDevice::onDataWrittenCallback(const GattWriteCallbackParams *params) {
+ if ((uart != NULL) && (params->handle == uart->getTXCharacteristicHandle())) {
+ uint16_t bytesRead = params->len;
+
+ printf("received %u bytes\n\r ", bytesRead);
+
+ if(bytesRead >= 255){
+ printf("Overflow command %u n\r ", bytesRead);
+ bytesRead = 255;
+ }
+
+ unsigned index = 0;
+ for (; index < bytesRead; index++) {
+ buffer[index] = params->data[index];
+ }
+
+ buffer[index++] = 0;
+
+ printf("Data : %s ",buffer);
+ printf("\r\n");
+ /* start echo in 50 ms */
+ _event_queue.call_in(50, this, &SMDevice::EchoBleUartReceived);
+ //_event_queue.call(EchoBleUartReceived);
+
+ }
+}
/** Blink LED to show we're running */
void SMDevice::blink(void)
{
@@ -284,9 +331,26 @@
GapAdvertisingData::COMPLETE_LOCAL_NAME,
DEVICE_NAME,
sizeof(DEVICE_NAME)
- );
+ );
+ /* Setup primary service */
+ uart = new UARTService(_ble);
+
- error = _ble.gap().setAdvertisingPayload(advertising_data);
+ /* add device name */
+ error = advertising_data.addData(
+ GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS ,
+ (const uint8_t *)UARTServiceUUID_reversed,
+ sizeof(sizeof(UARTServiceUUID_reversed))
+ );
+ /* setup advertising */
+ //error = _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
+ //ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
+ //error = _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
+ /* set up the services that can be discovered */
+ //error = _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));
+
+
+ //error = _ble.gap().setAdvertisingPayload(advertising_data);
if (error) {
printf("Error during Gap::setAdvertisingPayload\r\n");
@@ -297,8 +361,10 @@
_ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
/* how many milliseconds between advertisements, lower interval
* increases the chances of being seen at the cost of more power */
- _ble.gap().setAdvertisingInterval(20);
- _ble.gap().setAdvertisingTimeout(0);
+ //_ble.gap().setAdvertisingInterval(20);
+ //_ble.gap().setAdvertisingTimeout(0);
+ _ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
+ _ble.gap().setAdvertisingTimeout(300); /* 16 * 1000ms. */
error = _ble.gap().startAdvertising();
@@ -495,592 +561,3 @@
return 0;
}
#endif
-
-#ifdef OLD_BLE_SECURITY
-/* mbed Microcontroller Library
- * Copyright (c) 2006-2013 ARM Limited
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-//#ifdef BLE_SECURITY_ENABLED
-#include <events/mbed_events.h>
-#include <mbed.h>
-#include "ble/BLE.h"
-#include "ble/Gap.h"
-#include "Types.h"
-#include "ble/services/UARTService.h"
-
-//#include "ble/gap/Types.h"
-#include "SecurityManager.h"
-#include "pretty_printer.h"
-
-#if MBED_CONF_APP_FILESYSTEM_SUPPORT
-#include "LittleFileSystem.h"
-#include "HeapBlockDevice.h"
-#endif //MBED_CONF_APP_FILESYSTEM_SUPPORT
-
-/** This example demonstrates all the basic setup required
- * for pairing and setting up link security both as a central and peripheral
- *
- * The example is implemented as two classes, one for the peripheral and one
- * for central inheriting from a common base. They are run in sequence and
- * require a peer device to connect to. During the peripheral device demonstration
- * a peer device is required to connect. In the central device demonstration
- * this peer device will be scanned for and connected to - therefore it should
- * be advertising with the same address as when it connected.
- *
- * During the test output is written on the serial connection to monitor its
- * progress.
- */
-
-static const char DEVICE_NAME[] = "SM_device";
-
-/* we have to specify the disconnect call because of ambiguous overloads */
-//typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t);
-//const static disconnect_call_t disconnect_call = &Gap::disconnect;
-//typedef ble_error_t (Gap::*disconnect_call_t)(ble::connection_handle_t, ble::local_disconnection_reason_t);
-//const static (Gap::*disconnect_call_t) disconnect_call = &Gap::disconnect;
-
-/* for demonstration purposes we will store the peer device address
- * of the device that connects to us in the first demonstration
- * so we can use its address to reconnect to it later */
-static BLEProtocol::AddressBytes_t peer_address;
-
-/** Base class for both peripheral and central. The same class that provides
- * the logic for the application also implements the SecurityManagerEventHandler
- * which is the interface used by the Security Manager to communicate events
- * back to the applications. You can provide overrides for a selection of events
- * your application is interested in.
- */
-class SMDevice : private mbed::NonCopyable<SMDevice>,
- public SecurityManager::EventHandler,
- public Gap::EventHandler
-{
-public:
- SMDevice(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address) :
- _led1(LED1, 0),
- _ble(ble),
- _event_queue(event_queue),
- _peer_address(peer_address),
- _handle(0),
- _is_connecting(false) { };
-
- virtual ~SMDevice()
- {
- if (_ble.hasInitialized()) {
- _ble.shutdown();
- }
- };
-
- /** Start BLE interface initialisation */
- void run()
- {
- ble_error_t error;
-
- /* to show we're running we'll blink every 500ms */
- _event_queue.call_every(500, this, &SMDevice::blink);
-
- if (_ble.hasInitialized()) {
- printf("Ble instance already initialised.\r\n");
- return;
- }
-
- /* this will inform us off all events so we can schedule their handling
- * using our event queue */
- _ble.onEventsToProcess(
- makeFunctionPointer(this, &SMDevice::schedule_ble_events)
- );
-
- /* handle gap events */
- _ble.gap().setEventHandler(this);
-
- error = _ble.init(this, &SMDevice::on_init_complete);
-
- if (error) {
- printf("Error returned by BLE::init.\r\n");
- return;
- }
-
- /* this will not return until shutdown */
- _event_queue.dispatch_forever();
- };
-
-private:
- /** Override to start chosen activity when initialisation completes */
- virtual void start() = 0;
-
- /** This is called when BLE interface is initialised and starts the demonstration */
- void on_init_complete(BLE::InitializationCompleteCallbackContext *event)
- {
- ble_error_t error;
-
- if (event->error) {
- printf("Error during the initialisation\r\n");
- return;
- }
-
- /* This path will be used to store bonding information but will fallback
- * to storing in memory if file access fails (for example due to lack of a filesystem) */
- const char* db_path = "/fs/bt_sec_db";
- /* If the security manager is required this needs to be called before any
- * calls to the Security manager happen. */
- error = _ble.securityManager().init(
- true,
- false,
- SecurityManager::IO_CAPS_NONE,
- NULL,
- false,
- db_path
- );
-
- if (error) {
- printf("Error during init %d\r\n", error);
- return;
- }
-
- error = _ble.securityManager().preserveBondingStateOnReset(true);
-
- if (error) {
- printf("Error during preserveBondingStateOnReset %d\r\n", error);
- }
-
-#if MBED_CONF_APP_FILESYSTEM_SUPPORT
- /* Enable privacy so we can find the keys */
- error = _ble.gap().enablePrivacy(true);
-
- if (error) {
- printf("Error enabling privacy\r\n");
- }
-
- Gap::PeripheralPrivacyConfiguration_t configuration_p = {
- /* use_non_resolvable_random_address */ false,
- Gap::PeripheralPrivacyConfiguration_t::REJECT_NON_RESOLVED_ADDRESS
- };
- _ble.gap().setPeripheralPrivacyConfiguration(&configuration_p);
-
- Gap::CentralPrivacyConfiguration_t configuration_c = {
- /* use_non_resolvable_random_address */ false,
- Gap::CentralPrivacyConfiguration_t::RESOLVE_AND_FORWARD
- };
- _ble.gap().setCentralPrivacyConfiguration(&configuration_c);
-
- /* this demo switches between being master and slave */
- _ble.securityManager().setHintFutureRoleReversal(true);
-#endif
-
- /* Tell the security manager to use methods in this class to inform us
- * of any events. Class needs to implement SecurityManagerEventHandler. */
- _ble.securityManager().setSecurityManagerEventHandler(this);
-
- /* gap events also handled by this class */
- _ble.gap().setEventHandler(this);
-
- /* print device address */
- Gap::AddressType_t addr_type;
- Gap::Address_t addr;
- _ble.gap().getAddress(&addr_type, addr);
- print_address(addr);
-
- /* start test in 500 ms */
- _event_queue.call_in(500, this, &SMDevice::start);
- };
-
- /** Schedule processing of events from the BLE in the event queue. */
- void schedule_ble_events(BLE::OnEventsToProcessCallbackContext *context)
- {
- _event_queue.call(mbed::callback(&context->ble, &BLE::processEvents));
- };
-
- /** Blink LED to show we're running */
- void blink(void)
- {
- _led1 = !_led1;
- };
-
-private:
- /* Event handler */
-
- /** Respond to a pairing request. This will be called by the stack
- * when a pairing request arrives and expects the application to
- * call acceptPairingRequest or cancelPairingRequest */
- virtual void pairingRequest(
- ble::connection_handle_t connectionHandle
- ) {
- printf("Pairing requested - authorising\r\n");
- _ble.securityManager().acceptPairingRequest(connectionHandle);
- }
-
- /** Inform the application of a successful pairing. Terminate the demonstration. */
- virtual void pairingResult(
- ble::connection_handle_t connectionHandle,
- SecurityManager::SecurityCompletionStatus_t result
- ) {
- if (result == SecurityManager::SEC_STATUS_SUCCESS) {
- printf("Pairing successful\r\n");
- } else {
- printf("Pairing failed\r\n");
- }
- }
-
- /** Inform the application of change in encryption status. This will be
- * communicated through the serial port */
- virtual void linkEncryptionResult(
- ble::connection_handle_t connectionHandle,
- ble::link_encryption_t result
- ) {
- if (result == ble::link_encryption_t::ENCRYPTED) {
- printf("Link ENCRYPTED\r\n");
- } else if (result == ble::link_encryption_t::ENCRYPTED_WITH_MITM) {
- printf("Link ENCRYPTED_WITH_MITM\r\n");
- } else if (result == ble::link_encryption_t::NOT_ENCRYPTED) {
- printf("Link NOT_ENCRYPTED\r\n");
- }
-
- /* disconnect in 2 s */
- _event_queue.call_in(
- 2000,
- &_ble.gap(),
- &Gap::disconnect, //disconnect_call,
- _handle,
- (Gap::DisconnectionReason_t)0x13
- //Gap::DisconnectionReason_t::REMOTE_USER_TERMINATED_CONNECTION)
- //ble::local_disconnection_reason_t(ble::local_disconnection_reason_t::USER_TERMINATION)
- );
- }
-
-
-
- /** This is called by Gap to notify the application we disconnected,
- * in our case it ends the demonstration. */
- //virtual void onDisconnectionComplete(const Gap::DisconnectionCompleteEvent &)
- virtual void onDisconnectionComplete(const Gap::DisconnectionCallbackParams_t *params)
- {
- printf("Disconnected\r\n");
- _event_queue.break_dispatch();
- };
-
- //virtual void onAdvertisingEnd(const ble::AdvertisingEndEvent &)
- //void onAdvertisingEnd(const ble::AdvertisingEndEvent &)
- //{
- // printf("Advertising timed out - aborting\r\n");
- // _event_queue.break_dispatch();
- //}
-
- //virtual void onScanTimeout(const ble::ScanTimeoutEvent &)
- //{
- // printf("Scan timed out - aborting\r\n");
- // _event_queue.break_dispatch();
- //}
-
-private:
- DigitalOut _led1;
-
-protected:
- BLE &_ble;
- events::EventQueue &_event_queue;
- BLEProtocol::AddressBytes_t &_peer_address;
- ble::connection_handle_t _handle;
- bool _is_connecting;
-};
-
-/** A peripheral device will advertise, accept the connection and request
- * a change in link security. */
-class SMDevicePeripheral : public SMDevice {
-public:
- SMDevicePeripheral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
- : SMDevice(ble, event_queue, peer_address) { }
-
- virtual void start()
- {
- /* Set up and start advertising */
-#ifdef NEW_BLE5_API
- //uint8_t adv_buffer[Gap::LEGACY_ADVERTISING_MAX_SIZE];
- uint8_t adv_buffer[32];
- /* use the helper to build the payload */
- ble::Gap::AdvertisingDataBuilder adv_data_builder(
- adv_buffer, 32
- );
-
- adv_data_builder.setFlags();
- adv_data_builder.setName(DEVICE_NAME);
-
- /* Set payload for the set */
- ble_error_t error = _ble.gap().setAdvertisingPayload(
- ble::LEGACY_ADVERTISING_HANDLE,
- adv_data_builder.getAdvertisingData()
- );
-
- if (error) {
- print_error(error, "Gap::setAdvertisingPayload() failed");
- _event_queue.break_dispatch();
- return;
- }
-
- ble::gap::AdvertisingParameters adv_parameters(
- ble::advertising_type_t::CONNECTABLE_UNDIRECTED
- );
-
- error = _ble.gap().setAdvertisingParameters(
- ble::LEGACY_ADVERTISING_HANDLE,
- adv_parameters
- );
-
- if (error) {
- print_error(error, "Gap::setAdvertisingParameters() failed");
- return;
- }
-
- error = _ble.gap().startAdvertising(ble::LEGACY_ADVERTISING_HANDLE);
-
- if (error) {
- print_error(error, "Gap::startAdvertising() failed");
- return;
- }
-#else
- /* setup advertising */
- _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
- //_ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
- _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
- /* set up the services that can be discovered */
- _ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_128BIT_SERVICE_IDS,(const uint8_t *)UARTServiceUUID_reversed, sizeof(UARTServiceUUID_reversed));
- _ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
- _ble.gap().setAdvertisingInterval(1000); /* 1000ms. */
- _ble.gap().setAdvertisingTimeout(300); /* 16 * 1000ms. */
- _ble.gap().startAdvertising();
-
-#endif
- printf("Please connect to device\r\n");
-
- /** This tells the stack to generate a pairingRequest event
- * which will require this application to respond before pairing
- * can proceed. Setting it to false will automatically accept
- * pairing. */
- _ble.securityManager().setPairingRequestAuthorisation(true);
- };
-
- /** This is called by Gap to notify the application we connected,
- * in our case it immediately requests a change in link security */
- //virtual void onConnectionComplete(const ble::ConnectionCompleteEvent_t &event)
- virtual void onConnectionComplete(const Gap::ConnectionCallbackParams_t &event)
- {
- ble_error_t error;
-
- /* remember the device that connects to us now so we can connect to it
- * during the next demonstration */
- memcpy(_peer_address, event.peerAddr, 6);
-
- printf("Connected to peer: ");
- print_address(event.peerAddr);
-
- _handle = event.handle;
-
- /* Request a change in link security. This will be done
- * indirectly by asking the master of the connection to
- * change it. Depending on circumstances different actions
- * may be taken by the master which will trigger events
- * which the applications should deal with. */
- error = _ble.securityManager().setLinkSecurity(
- _handle,
- SecurityManager::SECURITY_MODE_ENCRYPTION_NO_MITM
- );
-
- if (error) {
- printf("Error during SM::setLinkSecurity %d\r\n", error);
- return;
- }
- };
-};
-
-/** A central device will scan, connect to a peer and request pairing. */
-class SMDeviceCentral : public SMDevice {
-public:
- SMDeviceCentral(BLE &ble, events::EventQueue &event_queue, BLEProtocol::AddressBytes_t &peer_address)
- : SMDevice(ble, event_queue, peer_address) { }
-
- virtual void start()
- {
- ble::ScanParameters params;
- ble_error_t error = _ble.gap().setScanParameters(params);
-
- if (error) {
- print_error(error, "Error in Gap::startScan %d\r\n");
- return;
- }
-
- /* start scanning, results will be handled by onAdvertisingReport */
- error = _ble.gap().startScan();
-
- if (error) {
- print_error(error, "Error in Gap::startScan %d\r\n");
- return;
- }
-
- printf("Please advertise\r\n");
-
- printf("Scanning for: ");
- print_address(_peer_address);
- }
-
-private:
- /* Gap::EventHandler */
-
- /** Look at scan payload to find a peer device and connect to it */
- virtual void onAdvertisingReport(const Gap::AdvertisementCallbackParams_t &event)
- {
- /* don't bother with analysing scan result if we're already connecting */
- if (_is_connecting) {
- return;
- }
-
- /* parse the advertising payload, looking for a discoverable device */
- if (memcmp(event.peerAddr, _peer_address, sizeof(_peer_address)) == 0) {
- ble_error_t error = _ble.gap().stopScan();
-
- if (error) {
- print_error(error, "Error caused by Gap::stopScan");
- return;
- }
-
- ble::ConnectionParameters connection_params(
- ble::phy_t::LE_1M,
- ble::scan_interval_t(50),
- ble::scan_window_t(50),
- ble::conn_interval_t(50),
- ble::conn_interval_t(100),
- ble::slave_latency_t(0),
- ble::supervision_timeout_t(100)
- );
- connection_params.setOwnAddressType(ble::own_address_type_t::RANDOM);
-
- error = _ble.gap().connect(
- event.getPeerAddressType(),
- event.getPeerAddress(),
- connection_params
- );
-
- if (error) {
- print_error(error, "Error caused by Gap::connect");
- return;
- }
-
- /* we may have already scan events waiting
- * to be processed so we need to remember
- * that we are already connecting and ignore them */
- _is_connecting = true;
-
- return;
- }
- }
-
- /** This is called by Gap to notify the application we connected,
- * in our case it immediately request pairing */
- virtual void onConnectionComplete(const Gap::ConnectionCallbackParams_t &event)
- {
- if (event.getStatus() == BLE_ERROR_NONE) {
- /* store the handle for future Security Manager requests */
- _handle = event.getConnectionHandle();
-
- printf("Connected\r\n");
-
- /* in this example the local device is the master so we request pairing */
- ble_error_t error = _ble.securityManager().requestPairing(_handle);
-
- if (error) {
- printf("Error during SM::requestPairing %d\r\n", error);
- return;
- }
-
- /* upon pairing success the application will disconnect */
- }
-
- /* failed to connect - restart scan */
- ble_error_t error = _ble.gap().startScan();
-
- if (error) {
- print_error(error, "Error in Gap::startScan %d\r\n");
- return;
- }
- };
-};
-
-
-#if MBED_CONF_APP_FILESYSTEM_SUPPORT
-bool create_filesystem()
-{
- static LittleFileSystem fs("fs");
-
- /* replace this with any physical block device your board supports (like an SD card) */
- static HeapBlockDevice bd(4096, 256);
-
- int err = bd.init();
-
- if (err) {
- return false;
- }
-
- err = bd.erase(0, bd.size());
-
- if (err) {
- return false;
- }
-
- err = fs.mount(&bd);
-
- if (err) {
- /* Reformat if we can't mount the filesystem */
- printf("No filesystem found, formatting...\r\n");
-
- err = fs.reformat(&bd);
-
- if (err) {
- return false;
- }
- }
-
- return true;
-}
-#endif //MBED_CONF_APP_FILESYSTEM_SUPPORT
-#ifdef BLE_MAIN
-int main()
-{
- BLE& ble = BLE::Instance();
- events::EventQueue queue;
-
-#if MBED_CONF_APP_FILESYSTEM_SUPPORT
- /* if filesystem creation fails or there is no filesystem the security manager
- * will fallback to storing the security database in memory */
- if (!create_filesystem()) {
- printf("Filesystem creation failed, will use memory storage\r\n");
- }
-#endif
-
- while(1) {
- {
- printf("\r\n PERIPHERAL \r\n\r\n");
- SMDevicePeripheral peripheral(ble, queue, peer_address);
- peripheral.run();
- }
-
- {
- printf("\r\n CENTRAL \r\n\r\n");
- SMDeviceCentral central(ble, queue, peer_address);
- central.run();
- }
- }
-
- return 0;
-}
-
-#endif
-
-#endif
\ No newline at end of file