Repository: Mentalab-hub/explorepy (language: python)

Issue:
Imp flag
Add impedance flag to explorepy.
Please test together with the corresponding [PR ](https://github.com/Mentalab-hub/explore-desktop/pull/58)in ExploreDesktop.


Discussion / hints:

Fix patch:
diff --git a/.bumpversion.cfg b/.bumpversion.cfg
index 0048977c..0b65be9b 100644
--- a/.bumpversion.cfg
+++ b/.bumpversion.cfg
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 1.6.0
+current_version = 1.6.1
 commit = False
 tag = False
 
diff --git a/.cookiecutterrc b/.cookiecutterrc
index 1e8a287d..84e9eddb 100644
--- a/.cookiecutterrc
+++ b/.cookiecutterrc
@@ -49,7 +49,7 @@ default_context:
     test_matrix_configurator:  'no'
     test_matrix_separate_coverage: 'no'
     test_runner:               'pytest'
-    travis:                    'yes'
+    travis:                    'no'
     version:                   '0.1.0'
     website:                   'https://mentalab.co/'
     year_from:                 '2018'
diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml
new file mode 100644
index 00000000..148a6f2b
--- /dev/null
+++ b/.github/workflows/linting.yml
@@ -0,0 +1,25 @@
+name: linting
+on:
+    pull_request:
+        branches: [master, develop]
+jobs:
+    linting:
+        name: Lint code
+        runs-on: ubuntu-latest
+        steps:
+            - name: Checkout source repository
+              uses: actions/checkout@v2
+              with:
+                  fetch-depth: 0
+
+            - name: lint the code
+              uses: ricardochaves/python-lint@v1.4.0
+              with:
+                  # Disable unnecessary linters (default flag is true)
+                  use-pylint: false
+                  use-pycodestyle: false
+                  use-black: false
+                  use-mypy: false
+                  # Activate required linters
+                  use-flake8: true
+                  use-isort: true
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 9959f261..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,62 +0,0 @@
-language: python
-cache: pip
-env:
-  global:
-    - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
-    - SEGFAULT_SIGNALS=all
-  matrix:
-    - TOXENV=check
-    - TOXENV=docs
-matrix:
-  include:
-    - python: '3.5'
-      env:
-        - TOXENV=py35,report
-    - python: '3.6'
-      env:
-        - TOXENV=py36,report
-    - python: '3.7'
-      dist: xenial
-      env:
-        - TOXENV=py37,report
-
-before_install:
-  - python --version
-  - uname -a
-  - lsb_release -a
-install:
-  - pip install tox
-  - virtualenv --version
-  - easy_install --version
-  - pip --version
-  - tox --version
-  - |
-    set -ex
-    if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then
-        (cd $HOME
-         wget https://bitbucket.org/pypy/pypy/downloads/pypy2-v6.0.0-linux64.tar.bz2
-         tar xf pypy2-*.tar.bz2
-         pypy2-*/bin/pypy -m ensurepip
-         pypy2-*/bin/pypy -m pip install -U virtualenv)
-        export PATH=$(echo $HOME/pypy2-*/bin):$PATH
-        export TOXPYTHON=$(echo $HOME/pypy2-*/bin/pypy)
-    fi
-    if [[ $TRAVIS_PYTHON_VERSION == 'pypy3' ]]; then
-        (cd $HOME
-         wget https://bitbucket.org/pypy/pypy/downloads/pypy3-v6.0.0-linux64.tar.bz2
-         tar xf pypy3-*.tar.bz2
-         pypy3-*/bin/pypy3 -m ensurepip
-         pypy3-*/bin/pypy3 -m pip install -U virtualenv)
-        export PATH=$(echo $HOME/pypy3-*/bin):$PATH
-        export TOXPYTHON=$(echo $HOME/pypy3-*/bin/pypy3)
-    fi
-    set +x
-script:
-  - tox -v
-after_failure:
-  - more .tox/log/* | cat
-  - more .tox/*/log/* | cat
-notifications:
-  email:
-    on_success: never
-    on_failure: always
diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst
index effed9be..6a80ab4c 100644
--- a/CONTRIBUTING.rst
+++ b/CONTRIBUTING.rst
@@ -2,8 +2,8 @@
 Contributing
 ============
 
-Contributions are welcome, and they are greatly appreciated! Every
-little bit helps, and credit will always be given.
+Contributions are welcome and appreciated! Every
+little helps, and credit will always be given.
 
 Bug reports
 ===========
@@ -17,74 +17,51 @@ When `reporting a bug <https://github.com/Mentalab-hub/explorepy/issues>`_ pleas
 Documentation improvements
 ==========================
 
-explorepy could always use more documentation, whether as part of the
-official explorepy docs, in docstrings, or even on the web in blog posts,
-articles, and such.
+We are happy to receive contributions to our documentation. Please do suggest changes to the
+official ``explorepy`` docs and docstrings, or increase our web presence with blog posts
+and articles.
 
 Feature requests and feedback
 =============================
 
-The best way to send feedback is to file an issue at https://github.com/Mentalab-hub/explorepy/issues.
+The best way to send feedback is to file an issue at: https://github.com/Mentalab-hub/explorepy/issues.
 
 If you are proposing a feature:
 
 * Explain in detail how it would work.
 * Keep the scope as narrow as possible, to make it easier to implement.
-* Remember that this is a volunteer-driven project, and that code contributions are welcome :)
 
 Development
 ===========
 
-To set up `explorepy` for local development:
+To set up ``explorepy`` for local development:
 
 1. Fork `explorepy <https://github.com/Mentalab-hub/explorepy>`_
    (look for the "Fork" button).
-2. Clone your fork locally::
 
-    git clone git@github.com:your_name_here/explorepy.git
+2. Clone your fork locally
+::
+    git clone git@github.com:USERNAME/explorepy.git
 
-3. Create a branch for local development::
-
-    git checkout -b name-of-your-bugfix-or-feature
-
-   Now you can make your changes locally.
-
-4. When you're done making changes, run all the checks, doc builder and spell checker with `tox <http://tox.readthedocs.io/en/latest/install.html>`_ one command::
-
-    tox
-
-5. Commit your changes and push your branch to GitHub::
+3. Create a branch for local development
+::
+    git checkout -b name-of-bugfix-or-feature
 
+4. Commit your changes and push your branch to GitHub
+::
     git add .
-    git commit -m "Your detailed description of your changes."
-    git push origin name-of-your-bugfix-or-feature
+    git commit -m "Detailed description of changes."
+    git push origin name-of-bugfix-or-feature
 
-6. Submit a pull request through the GitHub website.
+5. Submit a pull request to the develop branch through the GitHub website.
 
 Pull Request Guidelines
 -----------------------
 
-If you need some code review or feedback while you're developing the code just make the pull request.
-
-For merging, you should:
-
-1. Include passing tests (run ``tox``) [1]_.
-2. Update documentation when there's new API, functionality etc.
-3. Add a note to ``CHANGELOG.rst`` about the changes.
-4. Add yourself to ``AUTHORS.rst``.
-
-.. [1] If you don't have all the necessary python versions available locally you can rely on Travis - it will
-       `run the tests <https://travis-ci.org/Mentalab-hub/explorepy/pull_requests>`_ for each change you add in the pull request.
-
-       It will be slower though ...
-
-Tips
-----
-
-To run a subset of tests::
-
-    tox -e envname -- pytest -k test_myfeature
+For a code review or feedback, create a pull request to the develop branch.
 
-To run all the test environments in *parallel* (you need to ``pip install detox``)::
+For merge approval:
 
-    detox
+1. Update the documentation when appropriate.
+2. Add a note to ``CHANGELOG.rst`` about the changes.
+3. Add yourself to ``AUTHORS.rst``.
diff --git a/MANIFEST.in b/MANIFEST.in
index dfcf234e..387691fd 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -15,6 +15,6 @@ include LICENSE
 include README.rst
 recursive-include lib *
 
-include tox.ini .travis.yml appveyor.yml
+include tox.ini
 
 global-exclude *.py[cod] __pycache__  *.dylib
diff --git a/README.rst b/README.rst
index 8acaaee7..a0765369 100644
--- a/README.rst
+++ b/README.rst
@@ -5,24 +5,21 @@
 
 .. start-badges
 
-|docs| |version| |wheel| |supported-versions| |commits-since| |travis|
+|docs| |version| |wheel| |supported-versions| |commits-since|
 
 .. |docs| image:: https://readthedocs.org/projects/explorepy/badge/?style=flat
     :target: https://readthedocs.org/projects/explorepy
     :alt: Documentation Status
 
-.. |travis| image:: https://travis-ci.org/Mentalab-hub/explorepy.svg?branch=master
-    :alt: Travis-CI Build Status
-    :target: https://travis-ci.org/Mentalab-hub/explorepy
 
 .. |version| image:: https://img.shields.io/pypi/v/explorepy.svg
     :alt: PyPI Package latest release
     :target: https://pypi.org/project/explorepy
 
 
-.. |commits-since| image:: https://img.shields.io/github/commits-since/Mentalab-hub/explorepy/v1.6.0.svg
+.. |commits-since| image:: https://img.shields.io/github/commits-since/Mentalab-hub/explorepy/v1.6.1.svg
     :alt: Commits since latest release
-    :target: https://github.com/Mentalab-hub/explorepy/compare/v1.6.0...master
+    :target: https://github.com/Mentalab-hub/explorepy/compare/v1.6.1...master
 
 
 .. |wheel| image:: https://img.shields.io/pypi/wheel/explorepy.svg
@@ -41,23 +38,21 @@
 .. end-badges
 
 ==================
-Explorepy overview
+``explorepy`` overview
 ==================
 
-Explorepy is an open-source Python API designed to collect and process biosignal data using Mentalab’s Explore device. Amongst other things, Explorepy provides the following features:
-
-* Real-time streaming of ExG, orientation and environmental data
-* Real-time visualization
-* Data recording in CSV and BDF+ formats
-* LSL integration
-* Impedance measurement
-* Explore device configuration
+``explorepy`` is an open-source Python API designed to collect and process ExG data using Mentalab's Explore device. Amongst other things, ``explorepy`` provides the following features:
 
+* Real-time streaming of ExG, orientation and environmental data.
+* Real-time visualization of ExG, orientation and environmental data.
+* Data recording in CSV and BDF+ formats.
+* Integration with LabStreaming Layer.
+* Electrode impedance measurements.
+* Explore device configuration.
 
 Quick installation
 ==================
-For Windows users, the best way to install Explorepy is to download the latest Explorepy version from the
-the `release page <https://github.com/Mentalab-hub/explorepy/releases>`_ or use pip. Please note that dependencies will install automatically from the release page.
+For Windows users, the best way to install ``explorepy`` is to download the latest ``explorepy`` version from the `release page <https://github.com/Mentalab-hub/explorepy/releases>`_. Please note that dependencies will install automatically from the release page.
 
 For other operating systems, or to build the package manually on Windows, please refer to the information below.
 
@@ -65,9 +60,9 @@ For other operating systems, or to build the package manually on Windows, please
 Requirements
 ------------
 
-* Python 3.6 or newer versions
-* Visual Studio 2015 community edition (only Windows, in case of building the package)
-* Bluetooth header files (only Linux -> use this command: ``sudo apt-get install libbluetooth-dev``)
+* Python 3.6 to Python 3.9.
+* Visual Studio 2015 community edition (Windows only. For package building).
+* Bluetooth header files (Linux only. Use: ``sudo apt-get install libbluetooth-dev``).
 
 
 Detailed installation instructions can be found on the `installation page <https://explorepy.readthedocs.io/en/latest/installation.html>`_.
@@ -89,17 +84,19 @@ Get started
 
 CLI command
 -----------
-For a simple, quick start of Explorepy,  run:
-
-``explorepy acquire -n Explore_XXXX``
+To check ``explorepy`` is running use:
+::
+    explorepy acquire -n Explore_XXXX
 
-Enter ``explorepy -h`` for help.
+For help, use:
+::
+    explorepy -h
 
 
 Python code
 -----------
 
-When working in Python, the following connects to the Explore device and prints the data.
+In Python you can connect to the Explore device and print data using:
 
 ::
 
@@ -132,7 +129,7 @@ ECG with heart beat detection:
 Documentation
 =============
 
-For full API documentation, visit: https://explorepy.readthedocs.io/
+For full API documentation, visit: https://explorepy.readthedocs.io/.
 
 Troubleshooting
 ===============
diff --git a/ci/bootstrap.py b/ci/bootstrap.py
deleted file mode 100755
index e64a6c08..00000000
--- a/ci/bootstrap.py
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import os
-import sys
-from os.path import abspath
-from os.path import dirname
-from os.path import exists
-from os.path import join
-
-
-if __name__ == "__main__":
-    base_path = dirname(dirname(abspath(__file__)))
-    print("Project path: {0}".format(base_path))
-    env_path = join(base_path, ".tox", "bootstrap")
-    if sys.platform == "win32":
-        bin_path = join(env_path, "Scripts")
-    else:
-        bin_path = join(env_path, "bin")
-    if not exists(env_path):
-        import subprocess
-
-        print("Making bootstrap env in: {0} ...".format(env_path))
-        try:
-            subprocess.check_call(["virtualenv", env_path])
-        except subprocess.CalledProcessError:
-            subprocess.check_call([sys.executable, "-m", "virtualenv", env_path])
-        print("Installing `jinja2` into bootstrap environment...")
-        subprocess.check_call([join(bin_path, "pip"), "install", "jinja2"])
-    python_executable = join(bin_path, "python")
-    if not os.path.samefile(python_executable, sys.executable):
-        print("Re-executing with: {0}".format(python_executable))
-        os.execv(python_executable, [python_executable, __file__])
-
-    import jinja2
-
-    import subprocess
-
-    jinja = jinja2.Environment(
-        loader=jinja2.FileSystemLoader(join(base_path, "ci", "templates")),
-        trim_blocks=True,
-        lstrip_blocks=True,
-        keep_trailing_newline=True
-    )
-
-    tox_environments = [
-        line.strip()
-        # WARNING: 'tox' must be installed globally or in the project's virtualenv
-        for line in subprocess.check_output(['tox', '--listenvs'], universal_newlines=True).splitlines()
-    ]
-    tox_environments = [line for line in tox_environments if line not in ['clean', 'report', 'docs', 'check']]
-
-    for name in os.listdir(join("ci", "templates")):
-        with open(join(base_path, name), "w") as fh:
-            fh.write(jinja.get_template(name).render(tox_environments=tox_environments))
-        print("Wrote {}".format(name))
-    print("DONE.")
diff --git a/ci/templates/.travis.yml b/ci/templates/.travis.yml
deleted file mode 100644
index 03afa63a..00000000
--- a/ci/templates/.travis.yml
+++ /dev/null
@@ -1,59 +0,0 @@
-language: python
-cache: pip
-env:
-  global:
-    - LD_PRELOAD=/lib/x86_64-linux-gnu/libSegFault.so
-    - SEGFAULT_SIGNALS=all
-  matrix:
-    - TOXENV=check
-    - TOXENV=docs
-matrix:
-  include:
-{%- for env in tox_environments %}{{ '' }}
-    - python: '{{ env.split("-")[0] if env.startswith("pypy") else "{0[2]}.{0[3]}".format(env) }}'
-{% if env.startswith('py37') %}
-      dist: xenial
-{% endif %}
-      env:
-        - TOXENV={{ env }},report
-{%- endfor %}{{ '' }}
-before_install:
-  - python --version
-  - uname -a
-  - lsb_release -a
-install:
-  - pip install tox
-  - virtualenv --version
-  - easy_install --version
-  - pip --version
-  - tox --version
-  - |
-    set -ex
-    if [[ $TRAVIS_PYTHON_VERSION == 'pypy' ]]; then
-        (cd $HOME
-         wget https://bitbucket.org/pypy/pypy/downloads/pypy2-v6.0.0-linux64.tar.bz2
-         tar xf pypy2-*.tar.bz2
-         pypy2-*/bin/pypy -m ensurepip
-         pypy2-*/bin/pypy -m pip install -U virtualenv)
-        export PATH=$(echo $HOME/pypy2-*/bin):$PATH
-        export TOXPYTHON=$(echo $HOME/pypy2-*/bin/pypy)
-    fi
-    if [[ $TRAVIS_PYTHON_VERSION == 'pypy3' ]]; then
-        (cd $HOME
-         wget https://bitbucket.org/pypy/pypy/downloads/pypy3-v6.0.0-linux64.tar.bz2
-         tar xf pypy3-*.tar.bz2
-         pypy3-*/bin/pypy3 -m ensurepip
-         pypy3-*/bin/pypy3 -m pip install -U virtualenv)
-        export PATH=$(echo $HOME/pypy3-*/bin):$PATH
-        export TOXPYTHON=$(echo $HOME/pypy3-*/bin/pypy3)
-    fi
-    set +x
-script:
-  - tox -v
-after_failure:
-  - more .tox/log/* | cat
-  - more .tox/*/log/* | cat
-notifications:
-  email:
-    on_success: never
-    on_failure: always
diff --git a/docs/conf.py b/docs/conf.py
index c8e9fe94..2a256f9a 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -29,7 +29,7 @@
 year = '2018-2020'
 author = 'Mentalab GmbH.'
 copyright = '{0}, {1}'.format(year, author)
-version = release = '1.6.0'
+version = release = '1.6.1'
 
 pygments_style = 'trac'
 templates_path = ['.']
diff --git a/docs/installation.rst b/docs/installation.rst
index 55ded8f7..653cf5c0 100644
--- a/docs/installation.rst
+++ b/docs/installation.rst
@@ -2,106 +2,90 @@
 Installation
 ============
 
-
 Minimal Requirements
 ------------
-* Python 3.6 or newer version
+* Python 3.6 to Python 3.10
 * Microsoft Build Tools for Visual Studio 2019 (only Windows)
 * 6GB RAM (minimum 1GB *free* RAM during the session)
 * Intel i5 or higher (2x2.5GHz) CPU
 
-
 Recommended Requirements
 ------------
-* Python 3.6 or newer version
+* Python 3.6 to Python 3.10
 * Microsoft Build Tools for Visual Studio 2019 (only Windows)
 * 8GB RAM
 * Intel i7 or higher CPU
 
-
 How to install
 --------------
 
 Windows
 ^^^^^^^
 
-Option 1: Installing .exe file (for manual commands, basic use)
+Option 1: Installing .exe file (basic)
+""""""""
 
-This option is best for users who only intend to use ExplorePy from a command-line prompt.
- For example, if you are looking to quickly visualize and record data, use Option 1. 
- If you intend to add ExplorePy commands to a Python script
- (e.g. an experiment script), installing ExplorePy via Anaconda is a better solution.
+*This option is best for users who only intend to use* ``explorepy`` *from a command-line prompt.*
 
-For an overview of Explorepy commands, click `here <https://explorepy.readthedocs.io/en/latest/usage.html#command-line-interface>`_.
+For example, if you want to quickly visualize and record data, use Option 1.
+If you intend to add ``explorepy`` commands to a Python script
+(e.g. an experiment script), install ``explorepy`` via Anaconda instead.
 
-On a Windows machine, Explorepy can be installed using the .exe installable file uploaded to
-Explorepy's `release page <https://github.com/Mentalab-hub/explorepy/releases/download/v1.5.0/MentaLab_ExplorePy_1.5.0.exe>`_. Please note that the dependencies will be installed automatically.
+For an overview of ``explorepy`` commands, click `here <https://explorepy.readthedocs.io/en/latest/usage.html#command-line-interface>`_.
 
+On a Windows machine, ``explorepy`` can be installed using the .exe installable file uploaded to
+``explorepy``'s `release page <https://github.com/Mentalab-hub/explorepy/releases/download/v1.5.0/MentaLab_ExplorePy_1.5.0.exe>`_. Please note that the dependencies will be installed automatically.
 
-Option 2: Installing from Python Package Index (PyPI) and pip (for use in Python scripts, more advanced)
+Option 2: Installing from Python Package Index (PyPI) and pip (advanced)
+""""""""
 
-This option is best for users who intend to include ExplorePy functionalities in their own Python scripts.
- For this, use `Anaconda <https://www.anaconda.com/>`_ to access ExplorePy.
+*This option is best for users who intend to include* ``explorepy`` *functionalities in their own Python scripts.*
 
-To install the ExplorePy API and all its dependencies using pip on Windows:
+To install the ``explorepy`` API and all its dependencies using pip on Windows:
 
-1. Install Anaconda (or any other python distribution; these instructions pertain to Anaconda only). 
- Download and install the Anaconda Windows installer `here <https://www.anaconda.com/distribution/#download-section>`_.
-2. Install Microsoft Build Tools for Visual Studio 2019 `here <https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16>`_.
-    Select **Desktop development with C++** in the workloads tab. Make sure that  **MSVCv142 - VS 2019 C++ x64/x86 build tools** and latest version of **Windows 10 SDK** are checked.
+1. Install Anaconda (or any other Python distribution; these instructions pertain to Anaconda only). Download and install the `Anaconda Windows installer <https://www.anaconda.com/distribution/#download-section>`_.
+2. Install `Microsoft Build Tools for Visual Studio 2019 <https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools&rel=16>`_. Select *Desktop development with C++* in the workloads tab. Make sure that *MSVCv142 - VS 2019 C++ x64/x86 build tools* and the latest version of *Windows 10 SDK* are checked.
 3. Open the Conda command prompt.
-4. We recommend using a virtual environment.
+4. We recommend using a virtual environment. To do this:
 
-  * In Conda command prompt: ``conda create -n myenv python=3.7``
-  * Activate the virtual environment: ``conda activate myenv``
+   a. In Conda command prompt: ``conda create -n myenv python=3.8``
+   b. Activate the virtual environment: ``conda activate myenv``
 
 5. Upgrade your pip: ``python -m pip install --upgrade pip``
-6. To install ``explorepy`` from PyPI run: ``pip install explorepy``
-
+6. Run: ``pip install explorepy``, to install ``explorepy`` from PyPI.
 
 Ubuntu
 ^^^^^^
 1. Install Bluetooth header files using ``sudo apt-get install libbluetooth-dev``
-2. It is best to install Anaconda. Download and install the Anaconda Python 3.7 Ubuntu installer `here <https://www.anaconda.com/distribution/#download-section>`_.
-3. We recommend using a virtual environment in Conda.
+2. We recommend installing Anaconda. Download and install the `Anaconda Python 3.7 Ubuntu installer <https://www.anaconda.com/distribution/#download-section>`_.
+3. We recommend using a virtual environment in Conda. To do this:
 
-  * In Conda command prompt: ``conda create -n myenv python=3.6``
-  * Activate the virtual environment: ``conda activate myenv``
+   a. In Conda command prompt: ``conda create -n myenv python=3.8``
+   b. Activate the virtual environment: ``conda activate myenv``
 
 4. Upgrade your pip: ``python -m pip install --upgrade pip``
-5. To install ``explorepy`` from PyPI run: ``pip install explorepy``
-
+5. Run: ``pip install explorepy``, to install ``explorepy`` from PyPI.
 
 Mac
 ^^^
-1. Install XCode from the Mac App store. For this, you may need to upgrade to the latest version of MacOS.
-For older versions of MacOS, you can find compatible versions of XCode `here <https://en.wikipedia.org/wiki/Xcode>`_.
-All old Xcode versions are available `here <https://developer.apple.com/download/more/>`_.
-
+1. Install ``XCode`` from the Mac App store. For this, you may need to upgrade to the latest version of MacOS. For older versions of MacOS, find compatible versions of ``XCode`` `here <https://en.wikipedia.org/wiki/Xcode>`_. All old ``XCode`` versions are available `here <https://developer.apple.com/download/more/>`_.
 2. Accept the license agreement: ``sudo xcodebuild -license``
-
-3. It is best to install Anaconda. Download  and install the Anaconda Python 3.7 Mac installer `here <https://www.anaconda.com/distribution/#download-section>`_. For older versions of MacOS, compatible version of Anaconda can be found in `this table <https://docs.continuum.io/anaconda/install/#old-os>`_ and can be downloaded from `here <https://repo.anaconda.com/archive/index.html>`_.
-
+3. It is best to install Anaconda. Download  and install the `Anaconda Python 3.7 Mac installer <https://www.anaconda.com/distribution/#download-section>`_. For older versions of MacOS, compatible version of Anaconda can be found in `this table <https://docs.continuum.io/anaconda/install/#old-os>`_ and downloaded `here <https://repo.anaconda.com/archive/index.html>`_.
 4. We recommend using a virtual environment in Conda.
 
-  * In Conda command prompt: ``conda create -n myenv python=3.6``
-  * Activate the virtual environment: ``conda activate myenv``
+   a. In Conda command prompt: ``conda create -n myenv python=3.8``
+   b. Activate the virtual environment: ``conda activate myenv``
 
 5. Upgrade your pip: ``python -m pip install --upgrade pip``
-6. To install ``explorepy`` from PyPI run: ``pip install explorepy``
-
+6. Run: ``pip install explorepy``, to install ``explorepy`` from PyPI.
 
 Quick test
 ----------
 
-* •	Open the Conda command prompt (if you used pip) or Windows command prompt (if you used the installable file)
-
-* Activate the virtual environment (this step is only for Conda command prompt): ``conda activate myenv``
-
-* Run ``explorepy visualize -n <YOUR-DEVICE-NAME> -lf 1 -hf 40``
-
-* To stop visualization press Ctrl+c
-
+* Open the Conda command prompt (if you used pip) or Windows command prompt (if you used the installable file).
+* Activate the virtual environment (this step is only necessary in the Conda command prompt): ``conda activate myenv``
+* Run ``explorepy visualize -n DEVICE-NAME -lf 1 -hf 40``
+* To stop visualization press ``Ctrl+C``
 
 Troubleshooting
 ---------------
@@ -114,11 +98,11 @@ Troubleshooting
     OSError: [WinError 126] The specified module could not be found
 
 
-To fix this problem, an older version of Pylsl can be installed using this command: ::
+Solution: Install an older version of Pylsl. To do this, run: ::
 
     pip install pylsl==1.13.1
 
-Alternatively, MS Visual C++ redistributable (vc_redist) can be installed via this `download page <https://support.microsoft.com/en-ca/help/2977003/the-latest-supported-visual-c-downloads>`_.
+Alternatively, install `MS Visual C++ redistributable (vc_redist) <https://support.microsoft.com/en-ca/help/2977003/the-latest-supported-visual-c-downloads>`_.
 
 --------------------
 
@@ -138,7 +122,7 @@ Alternatively, MS Visual C++ redistributable (vc_redist) can be installed via th
     File "c:\users\jose\anaconda3\lib\asyncio\events.py", line 501, in add_reader
         raise NotImplementedError
 
-Solution: Downgrade Anaconda distribution version to one of 3.6 or 3.7 versions.
+Solution: Downgrade your Anaconda distribution to version 3.6 or 3.7.
 
 ---------------------
 
@@ -158,26 +142,34 @@ Solution: Downgrade Anaconda distribution version to one of 3.6 or 3.7 versions.
     ERROR: Command errored out with exit status 4294967295: python setup.py egg_info Check the logs for full command output.
 
 
-Solution: To fix this error, install numpy separately by ``pip install numpy`` and then install explorepy.
+Solution: Install numpy separately using ``pip install numpy`` and then install ``explorepy``.
 
+---------------------
 
 **4. OSError: A socket operation was attempted to an unreachable network.**
 
-Solution: Make sure that the device is paired with your computer and try again.
+Solution: Ensure that your Explore device is paired with your computer and try again.
+
+---------------------
 
 **5. ValueError: Error opening socket.**
 
-Solution: Make sure the Bluetooth module of operating system is on and working.
+Solution: Ensure the Bluetooth module of your computer's operating system is on and working.
+
+---------------------
 
 **6. OSError: The handle is invalid.**
 
-Solution: Make sure the Bluetooth module of operating system is on and working.
+Solution: Ensure the Bluetooth module of your computer's operating system is on and working.
+
+---------------------
 
 **7. DeviceNotFoundError: No device found with the name: Explore_####**
 
-Solution: Make sure the device is on and in advertising mode (blinking in blue at 1Hz). If the Bluetooth module of your
-computer is off, you may also get this error.
+Solution: Ensure your Explore device is on and in advertising mode (blinking in blue at 1Hz).
+
+You may also get this error if your computer's Bluetooth module is off.
 
 ---------------------
 
-If the issues persist, please send a screenshot and brief error description to support@mentalab.com, and we will quickly help you solve it.
+If your issue persists, please send a screenshot and brief error description to support@mentalab.com, and we will quickly help you solve it.
diff --git a/docs/usage.rst b/docs/usage.rst
index 2bfbef96..cfe0961f 100644
--- a/docs/usage.rst
+++ b/docs/usage.rst
@@ -7,7 +7,11 @@ Command Line Interface
 **Command structure:**
 ``explorepy <command> [args]``
 
-You can get help for a specific command by  ``explorepy <command> -h``. For example to get help about visualize command, run ``explorepy visualize -h`` will result to::
+Get help for a specific command using
+::
+    explorepy <command> -h
+For example to get help about the visualize command, run: ``explorepy visualize -h``
+::
 
     Usage: explorepy visualize [OPTIONS]
 
@@ -27,30 +31,35 @@ You can get help for a specific command by  ``explorepy <command> -h``. For exam
 Available Commands
 """"""""""""""""""
 
-**find-device**
-Scans for nearby Mentalab Explore devices. Prints out Name and MAC address of the found devices.
+find-device
+%%%%
+Scans for nearby Mentalab Explore devices. Prints out the Name and MAC address of found devices.
 
     Options:
       -h, --help                      Show this message and exit.
 
-.. note:: On Windows, this function may print all the paired devices.
+.. note:: On Windows, this command prints all paired devices.
 
 
-**acquire**::
-
-    Connect to a device with selected name or address. Only one input is necessary.
+acquire
+%%%%
+Connects to a device with selected name or address. Only one input is necessary.
+::
 
     Options:
       -a, --address TEXT  Explore device's MAC address
       -n, --name TEXT     Name of the device
       -h, --help          Show this message and exit.
 
+Example:
+::
+    explorepy acquire -n Explore_XXXX  # Put your device Bluetooth name
 
+record-data
+%%%%
 
-**record-data**
-
-Connects to a device and records ExG and orientation data into two separate files. Note that in CSV mode there will be
-an extra file for the marker events. In EDF mode, the data is actually recorded in BDF+ format (in 24-bit resolution).::
+Connects to a device and records ExG and orientation data into two separate files. In EDF mode, the data is actually recorded in BDF+ format (in 24-bit resolution). Note that in CSV mode there will be two extra files. One for the marker events, and one for the metadata.
+::
 
     Options:
       -a, --address TEXT              Explore device's MAC address
@@ -63,29 +72,29 @@ an extra file for the marker events. In EDF mode, the data is actually recorded
       -h, --help                      Show this message and exit.
 
 
-.. note:: If the sampling rate or channel mask has been changed during the recording, Explorepy will create a new EDF/CSV
-            file for ExG data with the given file name plus the time the setting has changed.
+.. note:: If you change your device's sampling rate or channel mask during recording, ``explorepy`` will create a new CSV file for ExG data with the given file name plus the time the setting changed.
+
+.. note:: To load EDF files, you can use `pyedflib <https://github.com/holgern/pyedflib>`_ or `mne <https://github.com/mne-tools/mne-python>`_ (for mne, you may need to change the file extension to ``bdf`` manually) in Python.
+
+          EEGLAB's BIOSIG plugin has problems with some EDF files (see this `issue <https://github.com/sccn/eeglab/issues/103>`_). To resolve this, download a precompiled MATLAB file (mexSLOAD.mex) from BIOSIG `here <https://pub.ist.ac.at/~schloegl/src/mexbiosig/>`_. Documentation is `here <http://biosig.sourceforge.net/help/biosig/t200/sload.html>`_.
 
-.. note:: To load EDF files, you can use `pyedflib <https://github.com/holgern/pyedflib>`_ or
-            `mne <https://github.com/mne-tools/mne-python>`_ (file extension may need to change to bdf manually for mne)
-            in python.
+.. note:: Because environmental factors, like temperature, can affect your device's sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and ``explorepy``'s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
 
-            EEGLAB's BIOSIG plugin has problem with some EDF files currently
-            (see this `issue <https://github.com/sccn/eeglab/issues/103>`_). A precompiled MATLAB code (mexSLOAD.mex)
-            from BIOSIG can be downloaded from this `link <https://pub.ist.ac.at/~schloegl/src/mexbiosig/>`_. The
-            documentaion can be found in this `link <http://biosig.sourceforge.net/help/biosig/t200/sload.html>`_.
+           If you are setting markers, use CSV. Alternatively, push data to LSL and record with `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. Avoid EDF files here, as they cannot guarantee precise timing.
 
-.. note:: As the environmental factors such as temperature may affect the sampling rate of the ADC, we recommend to
-            compute the sampling rate of the recorded data. In case of deviations, the signal must be resampled to
-            correct drifts. The timestamps in the csv/edf file can be used to compute the resampling factor.
+.. note:: If the Bluetooth connection is unstable, data may not arrive in order. Timestamps in the recorded files can be
+            used to sort the samples according to their precise sampling time in the device.
 
-            If you are setting markers in the recording, it is recommended to record in CSV file. Alternative option would
-            be pushing data to LSL and recording with
-            `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. EDF might not give a
-            precise timing for markers, hence it should be avoided.
 
-**push2lsl**
-Streams data to Lab Streaming Layer (LSL).::
+Example:
+::
+    explorepy record-data -n Explore_XXXX -f test_file --edf -ow
+
+push2lsl
+%%%%
+
+Streams data to Lab Streaming Layer (LSL).
+::
 
     Options:
       -a, --address TEXT        Explore device's MAC address
@@ -93,10 +102,15 @@ Streams data to Lab Streaming Layer (LSL).::
       -d, --duration <integer>  Streaming duration in seconds
       -h, --help                Show this message and exit.
 
+Example:
+::
+    explorepy push2lsl -n Explore_XXXX
 
+bin2csv
+%%%%
 
-**bin2csv**
-Takes a Binary file and converts it to three CSV files (ExG, orientation and marker files)::
+Takes a binary file and converts it to four CSV files (ExG, orientation, marker files and metadata).
+::
 
     Options:
       -f, --filename PATH  Name of (and path to) the binary file.  [required]
@@ -105,45 +119,46 @@ Takes a Binary file and converts it to three CSV files (ExG, orientation and mar
 
 
 
-.. note:: For devices with firmware version 2.1.1 and lower, Explorepy v0.5.0 has to be used to convert binary files.
+.. note:: For devices with firmware version 2.1.1 and lower, use ``explorepy`` v0.5.0 to convert binary files.
+
+.. note:: If you change your device's sampling rate or channel mask during recording, ``explorepy`` will create a new CSV file for ExG data with the given file name plus the time the setting changed.
 
-.. note:: If the sampling rate or channel mask has been changed during the recording, Explorepy will create a new CSV
-            file for ExG data with the given file name plus the time the setting has changed.
+Example:
+::
+    explorepy bin2csv -f input_file.BIN
 
-**bin2edf**
-Takes a Binary file and converts it to two EDF files (ExG and orientation - markers will be written in ExG file).
-The data is actually recorded in BDF+ format (in 24-bit resolution).::
+bin2edf
+%%%%
+
+Takes a binary file and converts it to two EDF files (ExG and orientation - markers will be written in ExG file). The data is actually recorded in BDF+ format (in 24-bit resolution).
+::
 
     Options:
       -f, --filename PATH  Name of (and path to) the binary file.  [required]
       -ow, --overwrite     Overwrite existing file
       -h, --help           Show this message and exit.
 
-.. note:: For devices with firmware version 2.1.1 and lower, explorepy v0.5.0 has to be used to convert binary files.
+.. note:: For devices with firmware version 2.1.1 and lower, use ``explorepy`` v0.5.0 to convert binary files.
+
+.. note:: To load EDF files, you can use `pyedflib <https://github.com/holgern/pyedflib>`_ or `mne <https://github.com/mne-tools/mne-python>`_ (for mne, you may need to change the file extension to ``bdf`` manually) in Python.
+
+          EEGLAB's BIOSIG plugin has problems with some EDF files (see this `issue <https://github.com/sccn/eeglab/issues/103>`_). To resolve this, download a precompiled MATLAB file (mexSLOAD.mex) from BIOSIG `here <https://pub.ist.ac.at/~schloegl/src/mexbiosig/>`_. Documentation is `here <http://biosig.sourceforge.net/help/biosig/t200/sload.html>`_.
 
-.. note:: To load EDF files, you can use `pyedflib <https://github.com/holgern/pyedflib>`_ or
-            `mne <https://github.com/mne-tools/mne-python>`_ (file extension may need to change to bdf manually for mne)
-            in python.
+.. note:: If you change your device's sampling rate or channel mask during recording, ``explorepy`` will create a new CSV file for ExG data with the given file name plus the time the setting changed.
 
-            EEGLAB's BIOSIG plugin has problem with some EDF files currently
-            (see this `issue <https://github.com/sccn/eeglab/issues/103>`_). A precompiled MATLAB code (mexSLOAD.mex)
-            from BIOSIG can be downloaded from this `link <https://pub.ist.ac.at/~schloegl/src/mexbiosig/>`_. The
-            documentaion can be found in this `link <http://biosig.sourceforge.net/help/biosig/t200/sload.html>`_.
+.. note:: Because environmental factors, like temperature, can affect your device's sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and ``explorepy``'s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
 
-.. note:: If the sampling rate or channel mask has been changed during the recording, Explorepy will create a new EDF
-            file for ExG data with the given file name plus the time the setting has changed.
+           If you are setting markers, use CSV. Alternatively, push data to LSL and record with `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. Avoid EDF files here, as they cannot guarantee precise timing.
 
-.. note:: As the environmental factors such as temperature may affect the sampling rate of the ADC, we recommend to
-            compute the sampling rate of the recorded data. In case of deviations, the signal must be resampled to
-            correct drifts. The timestamps in the csv/edf file can be used to compute the resampling factor.
+Example (overwrite):
+::
+    explorepy bin2edf -f input_file.BIN -ow
 
-            If you are setting markers in the recording, it is recommended to record in CSV file. Alternative option would
-            be pushing data to LSL and recording with
-            `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. EDF might not give a
-            precise timing for markers, hence it should be avoided.
+visualize
+%%%%
 
-**visualize**
-Visualizes real-time data in a browser-based dashboard. Currently, Chrome is the supported and recommended browser. The visualization in IE and Edge might be very slow, and is not recommended.::
+Visualizes real-time data in a browser-based dashboard. Currently, Google Chrome is supported. Visualization in IE and Edge can be slow.
+::
 
     Options:
       -a, --address TEXT        Explore device's MAC address
@@ -153,9 +168,15 @@ Visualizes real-time data in a browser-based dashboard. Currently, Chrome is the
       -hf, --highfreq FLOAT     High cutoff frequency of bandpass/lowpass filter.
       -h, --help                Show this message and exit.
 
+Example:
+::
+    explorepy visualize -n Explore_XXXX -lf .5 -hf 40 -nf 50
 
-**impedance**
-Visualizes the electrode impedances in a browser  dashboard. Currently, Chrome is the supported browser.::
+impedance
+%%%%
+
+Visualizes electrode impedances in a browser dashboard. Currently, Google Chrome is supported.
+::
 
     Options:
       -a, --address TEXT        Explore device's MAC address
@@ -163,18 +184,22 @@ Visualizes the electrode impedances in a browser  dashboard. Currently, Chrome i
       -h, --help                Show this message and exit.
 
 
-.. note::  It is recommended to restart the device after impedance measurement as the mechanism may introduce external noise.
 
-.. note:: Impedance value shown for each electrode is the sum of impedances of ground electrode and corresponding ExG electrode.
+.. note:: Impedance values depend on the impedance of the reference electrode. The value shown for each electrode is the average of the ground and ExG electrodes' impedances.
+
+            If all channel impedances are high, try cleaning the skin under the reference electrode more thoroughly using, e.g., alcohol, abrasive gel, or EEG.
+
+.. note:: Impedance values are subject to environmental conditions like noise and temperature. Aim for regular room temperatures (~15-25 degree celsius).
 
-.. note::  The accuracy of measured impedances are subject to environmental conditions such as noise and temperature.
+Example:
+::
+    explorepy impedance -n Explore_XXXX
 
+calibrate-orn
+%%%%
 
-**calibrate-orn**
-Calibrate the orientation module of the specified device. After running this module, calibration parameters will be
-stored in the configuration file of Explorepy. If the orientation module is calibrated, Explorepy computes the physical
-orientation (degree and rotation axis). Currently, the physical orientation data is not visualized in the dashboard and
-it is only accessible in python scripts in data packets.::
+Calibrates the orientation module of a device. This module stores calibration parameters in ``explorepy``'s configuration file. Once calibrated, ``explorepy`` computes the device's orientation (degree and rotation axis).
+::
 
     Options:
       -a, --address TEXT   Explore device's MAC address
@@ -183,31 +208,46 @@ it is only accessible in python scripts in data packets.::
       -h, --help           Show this message and exit.
 
 
-**format-memory**
-This command formats the memory of the specified Explore device.::
+format-memory
+%%%%
+
+Formats device memory.
+::
 
     Options:
       -a, --address TEXT  Explore device's MAC address
       -n, --name TEXT     Name of the device
       -h, --help          Show this message and exit.
 
+Example:
+::
+    explorepy format-memory -n Explore_XXXX
+
+set-sampling-rate
+%%%%
 
-**set-sampling-rate**
-This command sets the sampling rate of ExG on the specified Explore device. Acceptable values for
-sampling rates are 250, 500 or 1000. The default sampling rate of the device is 250 Hz. Please note that 1000 Hz sampling rate is in beta phase.::
+Sets a device's ExG sampling rate. Acceptable values: 250, 500 or 1000 (beta). The default sampling rate is 250 Hz.
+::
 
     Options:
       -a, --address TEXT              Explore device's MAC address
       -n, --name TEXT                 Name of the device
-      -sr, --sampling-rate [250|500|1000]
-                                      Sampling rate of ExG channels, it can be 250
-                                      or 500  [required]
+      -sr, --sampling-rate [250 | 500 | 1000]
+                                      Sampling rate of ExG channels, it can be 250,
+                                      500 or 1000 [required]
       -h, --help                      Show this message and exit.
 
+Example:
+::
+    explorepy set-sampling-rate -n Explore_XXXX -sr 500
+
+set-channels
+%%%%
 
-**set-channels**
-Using this command, you can enable/disable a set of ExG channels of the device. A binary string is required for the
-channel mask, where LSB is channel 1 (eg. 00001111, to enable 4 channels of an 8-ch device).::
+Enables and disables a set of ExG channels. Takes a binary string to represent the channel mask (where the least significant/right-most bit represents channel 1).
+
+For example, to disable channels 5 to 8 of an 8 channel device, use ``00001111``.
+::
 
     Options:
       -a, --address TEXT              Explore device's MAC address
@@ -219,9 +259,15 @@ channel mask, where LSB is channel 1 (eg. 00001111, to enable 4 channels of an 8
                                       [required]
       -h, --help                      Show this message and exit.
 
-**disable-module**
-Using this command, you can disable a module of Explore device. Orientation, environment and ExG modules can be disabled
-with this command.::
+Example:
+::
+    explorepy set-channels -n Explore_XXXX -m 0111
+
+disable-module
+%%%%
+
+Disables a device module (orientation, environment and ExG).
+::
 
     Options:
       -a, --address TEXT  Explore device's MAC address
@@ -231,8 +277,11 @@ with this command.::
 
 
 
-**enable-module**
-If you have already disabled a module of Explore device, you can enable it with this command.::
+enable-module
+%%%%
+
+Enables a device module (orientation, environment and ExG).
+::
 
     Options:
       -a, --address TEXT  Explore device's MAC address
@@ -242,9 +291,11 @@ If you have already disabled a module of Explore device, you can enable it with
       -h, --help          Show this message and exit.
 
 
-**soft-reset**
-This command does a soft reset of the device. All the settings (e.g. sampling rate, channel mask)
-return to the default values.::
+soft-reset
+%%%%
+
+Soft resets a device. All settings (e.g. sampling rate, channel mask) return to default.
+::
 
     Options:
       -a, --address TEXT  Explore device's MAC address
@@ -252,111 +303,76 @@ return to the default values.::
       -h, --help          Show this message and exit.
 
 
-Example commands:
+All commands:
 """""""""""""""""
-Data acquisition: ``explorepy acquire -n Explore_XXXX  # Put your device Bluetooth name``
-
-Record data: ``explorepy record-data -n Explore_XXXX -f test_file --edf -ow``
-
-Push data to lsl: ``explorepy push2lsl -n Explore_XXXX``
-
-Convert a binary file to csv: ``explorepy bin2csv -f input_file.BIN``
-
-Convert a binary file to EDF and overwrite if files exist already: ``explorepy bin2edf -f input_file.BIN -ow``
+To see the full list of commands
+::
+    explorepy -h
 
-Visualize in real-time: ``explorepy visualize -n Explore_XXXX -lf .5 -hf 40 -nf 50``
 
-Impedance measurement: ``explorepy impedance -n Explore_XXXX``
-
-Format the memory: ``explorepy format-memory -n Explore_XXXX``
-
-Set the sampling rate: ``explorepy set-sampling-rate -n Explore_XXXX -sr 500``
-
-Set the channel mask: ``explorepy set-channels -n Explore_XXXX -m 0111``
-
-To see the full list of commands ``explorepy -h``.
-
-Python project
+Creating a Python project
 ^^^^^^^^^^^^^^
-To use explorepy in a python project::
-
+To use ``explorepy`` in a Python project:
+::
 	import explorepy
 
+.. note:: Because ``explorepy`` uses multithreading, running Python scripts in some consoles, such as Ipython's or Spyder's, can cause strange behaviours.
 
-.. note:: Since explorepy is using multithreading for data streaming, running python scripts in some consoles such
-            as Ipython's or Spyder's consoles may lead to strange behaviours.
-
-.. note:: To give you a better idea how you can develop your own python project based on Explorepy, we have provided
-            some sample projects in this `folder <https://github.com/Mentalab-hub/explorepy/tree/master/examples>`_.
+.. note:: For an exmaple project using ``explorepy``, see this `folder on GitHub <https://github.com/Mentalab-hub/explorepy/tree/master/examples>`_.
 
 
 Initialization
 """"""""""""""
-Before starting a session, make sure your device is paired to your computer. The device will be shown under the following name: Explore_XXXX,
-with the last 4 characters being the last 4 hex numbers of the devices MAC address.
+Before starting a session, ensure your device is paired to your computer. The device will display under the following: ``Explore_XXXX``.
 
-**Make sure to initialize the Bluetooth connection before streaming using the following lines**::
+**Be sure to initialize the Bluetooth connection before streaming:**
+::
 
     explore = explorepy.Explore()
     explore.connect(device_name="Explore_XXXX") # Put your device Bluetooth name
 
-Alternatively you can use the device's MAC address::
-
+Alternatively, use your device's MAC address.
+::
     explore.connect(mac_address="XX:XX:XX:XX:XX:XX")
 
-If the device is not found, you will receive an error.
-
+If the device cannot be found, you will receive an error.
 
 Streaming
 """""""""
-After connecting to the device you are able to stream data and print the data in the console.::
 
+After connecting to the device, you will be able to stream and print data to the console.
+::
     explore.acquire()
 
-
 Recording
 """""""""
-You can record data in realtime to EDF (BDF+) or CSV files::
 
+You can record data in realtime to EDF (BDF+) or CSV files using:
+::
     explore.record_data(file_name='test', duration=120, file_type='csv')
 
-This will record data in three separate files "test_ExG.csv", "test_ORN.csv" and "test_marker.csv" which contain ExG, orientation data (accelerometer, gyroscope, magnetometer) and event markers respectively. The duration of the recording can be specified (in seconds).
-If you want to overwrite already existing files, change the line above::
-
+This will record data in three separate files: "``test_ExG.csv``", "``test_ORN.csv``" and "``test_marker.csv``", which contain ExG data, orientation data (accelerometer, gyroscope, magnetometer) and event markers respectively. Add command arguments to overwrite files and set the duration of the recording (in seconds).
+::
     explore.record_data(file_name='test', do_overwrite=True, file_type='csv', duration=120)
 
+.. note:: To load EDF files, you can use `pyedflib <https://github.com/holgern/pyedflib>`_ or `mne <https://github.com/mne-tools/mne-python>`_ (for mne, you may need to change the file extension to ``bdf`` manually) in Python.
 
+          EEGLAB's BIOSIG plugin has problems with some EDF files (see this `issue <https://github.com/sccn/eeglab/issues/103>`_). To resolve this, download a precompiled MATLAB file (mexSLOAD.mex) from BIOSIG `here <https://pub.ist.ac.at/~schloegl/src/mexbiosig/>`_. Documentation is `here <http://biosig.sourceforge.net/help/biosig/t200/sload.html>`_.
 
-.. note:: To load EDF files, you can use `pyedflib <https://github.com/holgern/pyedflib>`_ or
-            `mne <https://github.com/mne-tools/mne-python>`_ (file extension may need to change to bdf manually for mne)
-            in python.
-
-            EEGLAB's BIOSIG plugin has problem with some EDF files currently
-            (see this `issue <https://github.com/sccn/eeglab/issues/103>`_). A precompiled MATLAB code (mexSLOAD.mex)
-            from BIOSIG can be downloaded from this `link <https://pub.ist.ac.at/~schloegl/src/mexbiosig/>`_. The
-            documentaion can be found in this `link <http://biosig.sourceforge.net/help/biosig/t200/sload.html>`_.
-
-.. note:: As the environmental factors such as temperature may affect the sampling rate of the ADC, we recommend to
-            compute the sampling rate of the recorded data. In case of deviations, the signal must be resampled to
-            correct drifts. The timestamps in the csv/edf file can be used to compute the resampling factor.
-
-            If you are setting markers in the recording, it is recommended to record in CSV file. Alternative option would
-            be pushing data to LSL and recording with
-            `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. EDF might not give a
-            precise timing for markers, hence it should be avoided.
+.. note:: Because environmental factors, like temperature, can affect your device's sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and ``explorepy``'s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
 
+           If you are setting markers, use CSV. Alternatively, push data to LSL and record with `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. Avoid EDF, as it cannot guarantee precise timing.
 
 Visualization
 """"""""""""""
-It is possible to visualize data in real-time in a browser-based dashboard by the following code. Currently, Chrome is the supported browser. The visualization in IE and Edge might be very slow::
-
 
+You can visualize real-time data in a browser-based dashboard using the following code. Currently, Google Chrome is supported. Visualization in IE and Edge can be slow.
+::
     explore.visualize(bp_freq=(1, 30), notch_freq=50)
 
-Where `bp_freq` and `notch_freq` determine cut-off frequencies of bandpass/lowpass/highpass filter and frequency of notch filter (either 50 or 60) respectively.
+``bp_freq`` specifies the cut-off frequencies of bandpass/lowpass/highpass filters.  ``notch_freq`` sets the notch filter (either 50 or 60).
 
-
-In the dashboard, you can set the signal visualization mode to EEG or ECG. EEG mode provides the spectral analysis plot of the signal. In ECG mode, the heartbeats are detected and heart rate is calculated from the RR-intervals.
+In the dashboard, you can set the signal visualization mode to either EEG or ECG. EEG mode provides the spectral analysis plot of the signal. ECG mode detects heartbeats and calculates heart rate using RR-intervals.
 
 EEG:
 
@@ -373,87 +389,108 @@ ECG with heart beat detection:
 
 Impedance measurement
 """""""""""""""""""""
-To measure electrodes impedances::
-
 
+You can measure electrodes impedances using:
+::
     explore.measure_imp()
 
-
 .. image:: /images/Dashboard_imp.jpg
   :width: 800
   :alt: Impedance Dashboard
 
-.. note:: Impedance value shown for each electrode is the sum of impedances of ground electrode and corresponding ExG electrode. This can make the impedances appear higher than they actually are. Make sure your ground is well prepared, when facing issues in getting to low impedances.
+.. note:: Impedance values depend on the impedance of the reference electrode. The value shown for each electrode is the average of the ground and ExG electrodes' impedances.
 
-.. note::  The accuracy of measured impedances are subject to environmental conditions such as noise and temperature. Therefore, this works best at regular room temperatures (~15-25 °C).
+            If all channel impedances are high, try cleaning the skin under the reference electrode more thoroughly using, e.g., alcohol, abrasive gel, or EEG.
 
-Labstreaminglayer (lsl)
+.. note:: Impedance values are subject to environmental conditions like noise and temperature. Aim for regular room temperatures (~15-25 degree celsius).
+
+Lab Streaming Layer (lsl)
 """""""""""""""""""""""
-You can push data directly to LSL using the following line::
 
+You can push data to LSL using:
+::
     explore.push2lsl()
 
+LSL allows you to stream data from your Explore device and third-parties, like OpenVibe or MATLAB, simultaneously. (See the `LabStreaming Layer docs <https://github.com/sccn/labstreaminglayer>`_ and `OpenVibe docs <http://openvibe.inria.fr/how-to-use-labstreaminglayer-in-openvibe/>`_ for more).
 
-With this, you can stream data from other software such as OpenVibe or other programming languages such as MATLAB, Java, C++ and so on. (See `labstreaminglayer <https://github.com/sccn/labstreaminglayer>`_, `OpenVibe <http://openvibe.inria.fr/how-to-use-labstreaminglayer-in-openvibe/>`_ documentations for details).
-This function creates three LSL streams for ExG, Orientation and markers.
-In case of a disconnect (device loses connection), the program will try to reconnect automatically.
-
+``push2lsl`` creates three LSL streams; one for each of ExG data, orientation data and marker events. If your device loses connection, ``explorepy`` will try to reconnect automatically.
 
 Converter
 """""""""
-It is also possible to extract BIN files from the device via USB. To convert these to CSV, you can use the function bin2csv, which takes your desired BIN file
-and converts it to 2 CSV files (one for orientation, the other one for ExG data). A Bluetooth connection is not needed for this. ::
 
+It is possible to extract BIN files from a device via USB. To convert these binary files to CSV, use ``bin2csv``. This function will create two CSV files (one for orientation, the other one for ExG data). A Bluetooth connection is not needed for this.
+::
     explore.convert_bin(bin_file='DATA001.BIN', file_type='csv', do_overwrite=False)
 
 
-.. note::  If the sampling rate or channel mask has been changed during the recording, Explorepy will create a new EDF/CSV
-            file for ExG data with the given file name plus the time the setting has changed.
+.. note:: If you change your device's sampling rate or channel mask during recording, ``explorepy`` will create a new CSV file for ExG data with the given file name plus the time the setting changed.
 
-.. note:: As the environmental factors such as temperature may affect the sampling rate of the ADC, we recommend to
-            compute the sampling rate of the recorded data. In case of deviations, the signal must be resampled to
-            correct drifts. The timestamps in the csv/edf file can be used to compute the resampling factor.
+.. note:: Because environmental factors, like temperature, can affect your device's sampling rate, we recommend computing the sampling rate of recorded data. If you find a deviation between the recorded sampling rate and ``explorepy``'s sampling rate, resample your signal to correct for drifts. The timestamps in the CSV/EDF file can be used to compute the resampling factor.
 
-            If you are setting markers in the recording, it is recommended to record in CSV file. Alternative option would
-            be pushing data to LSL and recording with
-            `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. EDF might not give a
-            precise timing for markers, hence it should be avoided.
+           If you are setting markers, use CSV. Alternatively, push data to LSL and record with `LabRecorder <https://github.com/labstreaminglayer/App-labrecorder/tree/master>`_. Avoid EDF, as it cannot guarantee precise timing.
 
 Event markers
 """""""""""""
-In addition to the marker event generated by pressing the button on Explore device, you can set markers in your code using the `explorepy.Explore.set_marker` function. However, this function must be called from a different thread than the parsing thread.
-Please not that marker codes between 0 and 7 are reserved for hardware related markers. You can use any other (integer) code for your marker from 8 to 65535.
-To see an example usage of this function look at `this script <https://github.com/Mentalab-hub/explorepy/tree/master/examples/marker_example.py>`_
+Event markers can be used to time synch data. The following table describes all types of event markers
+available for Explore device.
+
+.. list-table:: Event markers table
+    :widths: 25 25 50
+    :header-rows: 1
+
+    * - Type
+      - Code range
+      - Label in recordings
+    * - Push button
+      - 0-7
+      - pb_<CODE>
+    * - Software marker
+      - 0-65535
+      - sw_<CODE>
+    * - Trigger-in
+      - 0-65535
+      - in_<CODE>
+    * - Trigger-out
+      - 0-65535
+      - out_<CODE>
+
+In order to set markers programmatically, use:
+::
+    explore.set_marker(code=10)
+
+A simple example of software markers used in a script can be found `here <https://github.com/Mentalab-hub/explorepy/tree/master/examples/marker_example.py>`_.
 
 Device configuration
 """"""""""""""""""""
-Using methods of Explore class, the device settings can be changed.
 
-Explore's sampling rate can be changed to 250, 500 or 1000Hz (default sampling rate is 250Hz). ::
+You can programmatically change a device's settings.
 
+To change a device's sampling rate:
+::
     explore.set_sampling_rate(sampling_rate=500)
 
 
-Format memory: ::
-
+To format a device's memory:
+::
     explore.format_memory()
 
-The ExG input channels can be deactivated/activated using ``set_channels`` method. The (string) binary representation
-of a channel mask will be used to select channels (LSB is channel 1), e.g. 0b01000011 means channels 1,2,7 are active. ::
-
+To activate/deactivate ExG input channels:
+::
     explore.set_channels(channel_mask="01000011")
 
-or alternatively: ::
+.. note:: Represent the channel masks using a String of binary numbers. For example, ``01000011`` means channels 1,2,7 are active.
 
+Alternatively, use:
+::
     explore.set_channels(channel_mask=0b01000011)
 
 
-Orientation, ExG and environment modules can be disabled/enabled using ``disable_module``/``enable_module`` functions. ::
-
+To disabled/enable orientation, ExG or environment modules:
+::
     explore.disable_module(module_name='ORN')
     explore.enable_module(module_name='ENV')
 
 
-You can reset the device to the default settings by: ::
-
+To reset a device's settings:
+::
     explore.reset_soft()
diff --git a/examples/marker_example.py b/examples/marker_example.py
index 6bae9eca..2242d59b 100755
--- a/examples/marker_example.py
+++ b/examples/marker_example.py
@@ -1,6 +1,6 @@
+import time
 import explorepy
 import argparse
-import threading
 
 
 def main():
@@ -9,16 +9,18 @@ def main():
     args = parser.parse_args()
 
     # Create an Explore object
-    exp_device = explorepy.Explore()
+    explore = explorepy.Explore()
+    explore.connect(device_name=args.name)
+    explore.record_data(file_name='test_event_gen', file_type='csv', do_overwrite=True, block=False)
 
-    def marker_gen():
-        exp_device.set_marker(code=12)
-        threading.Timer(5, marker_gen).start()
+    n_markers = 20
+    interval = 2
 
-    exp_device.connect(device_name=args.name)
-    marker_gen()
-    exp_device.record_data(file_name='test_event_gen', duration=25, file_type='edf', do_overwrite=True, block=True)
-    print("Press Ctrl+c to exit.")
+    for i in range(n_markers):
+        explore.set_marker(code=i)
+        time.sleep(interval)
+
+    explore.stop_recording()
 
 
 if __name__ == "__main__":
diff --git a/examples/p300_demo/README.md b/examples/p300_demo/README.md
index e555d0a7..eb8f30f7 100644
--- a/examples/p300_demo/README.md
+++ b/examples/p300_demo/README.md
@@ -10,10 +10,11 @@ Experiment setup
 * Install required packages by running this command:
 `pip install matplotlib psychopy mne`
 * Download the code from this page.
-* In Conda terminal, navigate to `p300_demo` folder in the example directory of the Explorepy's code.
-* Setup the cap and electrodes. Place EEG electrodes on the desired positions (e.g. Cz, Pz, CP1, CP2, P3, P4, Oz, etc.) and the
+* In Conda terminal, navigate to `p300_demo` folder in the example directory of the Explorepy's code (e.g.
+`cd <YOUR-FOLDER>\explorepy-master\examples\p300_demo`).
+* Setup the cap and electrodes. Place EEG electrodes on the desired positions and the
 ground electrode on Mastoid (or any other location far enough from other electrodes).
-
+The default setup in the code is `ch1` to `ch8` and ground on `TP9`, `Cz`, `Pz`, `CP1`, `CP2`, `P3`, `P4`, `Oz` and `TP10` respectively.
 
 Experiment
 ----------
@@ -30,6 +31,17 @@ Make sure the device is on and in advertising mode before running the command. T
 there are 5 trials in each block (50 trials in total). The numbers can be changed in `experiment.py` script (`n_blocks` and
 `n_trials_per_block` variables).
 
+| Variable           | Default value |
+|--------------------|---------------|
+| Stimulus duration  | 500 ms        |
+| Number of blocks   | 10            |
+| Trials per block   | 5             |
+| Sampling rate      | 250           |
+| Number of channels | 8             |
+| Target marker code | 11            |
+|Non-target marker code|10           |
+
+
 When the experiment is completed, you will find three csv files (ExG, ORN and markers) in the working directory.
 
 Running `python analysis_csv.py -f rec_file_name` in the terminal will analyse the recorded data and generates the plots.
diff --git a/examples/p300_demo/analysis_csv_4_channel.py b/examples/p300_demo/analysis_csv_4_channel.py
new file mode 100644
index 00000000..7cbdc0f3
--- /dev/null
+++ b/examples/p300_demo/analysis_csv_4_channel.py
@@ -0,0 +1,117 @@
+import argparse
+import matplotlib.pyplot as plt
+import pandas as pd
+from scipy import signal
+import numpy as np
+
+CH_LABELS = ['P3', 'P4', 'CP1', 'CP2']
+
+
+def extract_epochs(sig, sig_times, event_times, t_min, t_max, fs):
+    """ Extracts epochs from signal
+    Args:
+        sig: EEG signal with the shape: (N_chan, N_sample)
+        sig_times: Timestamp of the EEG samples with the shape (N_sample)
+        event_times: Event marker times
+        t_min: Starting time of the epoch relative to the event time
+        t_max: End time of the epoch relative to the event time
+        fs: Sampling rate
+    Returns:
+        (numpy ndarray): EEG epochs
+    """
+    offset_st = int(t_min * fs)
+    offset_end = int(t_max * fs)
+    epoch_list = []
+    for i, event_t in enumerate(event_times):
+        idx = np.argmax(sig_times > event_t)
+        epoch_list.append(sig[:, idx + offset_st:idx + offset_end])
+    return np.array(epoch_list)
+
+
+def reject_bad_epochs(epochs, p2p_max):
+    """Rejects bad epochs based on a peak-to-peak amplitude criteria
+    Args:
+        epochs: Epochs of EEG signal
+        p2p_max: maximum peak-to-peak amplitude
+
+    Returns:
+        (numpy ndarray):EEG epochs
+    """
+    temp = epochs.reshape((epochs.shape[0], -1))
+    res = epochs[np.ptp(temp, axis=1) < p2p_max, :, :]
+    print(f"{temp.shape[0] - res.shape[0]} epochs out of {temp.shape[0]} epochs have been rejected.")
+    return res
+
+
+def custom_filter(exg, lf, hf, fs, type):
+    """
+    Args:
+        exg: EEG signal with the shape: (N_chan, N_sample)
+        lf: Low cutoff frequency
+        hf: High cutoff frequency
+        fs: Sampling rate
+        type: Filter type, 'bandstop' or 'bandpass'
+    Returns:
+        (numpy ndarray): Filtered signal (N_chan, N_sample)
+    """
+    N = 4
+    b, a = signal.butter(N, [lf / fs, hf / fs], type)
+    return signal.filtfilt(b, a, exg)
+
+
+def main():
+    parser = argparse.ArgumentParser(description="P300 analysis script")
+    parser.add_argument("-f", "--filename", dest="filename", type=str, help="Recorded file name")
+    args = parser.parse_args()
+    fs = 250
+    lf = .5
+    hf = 40
+
+    label_target = 11
+    label_nontarget = 10
+
+    t_min = -.3
+    t_max = 1.
+    p2p_max = 500000  # rejection criteria, units in uV
+
+    exg_filename = args.filename + '_ExG.csv'
+    marker_filename = args.filename + '_Marker.csv'
+
+    # Import data
+    exg = pd.read_csv(exg_filename)
+    markers = pd.read_csv(marker_filename)
+
+    ts_sig = exg['TimeStamp'].to_numpy()
+    ts_markers_nontarget = markers[markers.Code.isin([label_nontarget])]['TimeStamp'].to_numpy()
+    ts_markers_target = markers[markers.Code.isin([label_target])]['TimeStamp'].to_numpy()
+    sig = exg[['ch'+str(i) for i in range(1, 5)]].to_numpy().T
+    sig -= (sig[0, :]/2)
+    filt_sig = custom_filter(sig, 45, 55, fs, 'bandstop')
+    filt_sig = custom_filter(filt_sig, lf, hf, fs, 'bandpass')
+
+    target_epochs = extract_epochs(filt_sig, ts_sig, ts_markers_target, t_min, t_max, fs)
+    nontarget_epochs = extract_epochs(filt_sig, ts_sig, ts_markers_nontarget, t_min, t_max, fs)
+
+    target_epochs = reject_bad_epochs(target_epochs, p2p_max)
+    nontarget_epochs = reject_bad_epochs(nontarget_epochs, p2p_max)
+
+    erp_target = target_epochs.mean(axis=0)
+    erp_nontarget = nontarget_epochs.mean(axis=0)
+
+    t = np.linspace(t_min, t_max, erp_target.shape[1])
+    fig, axes = plt.subplots(nrows=2, ncols=2)
+    fig.tight_layout()
+    for i, ax in enumerate(axes.flatten()):
+        ax.plot(t, erp_nontarget[i, :], label='Non-target')
+        ax.plot(t, erp_target[i, :], 'tab:orange', label='Target')
+        ax.plot([0, 0], [-30, 30], linestyle='dotted', color='black')
+        ax.set_ylabel('\u03BCV')
+        ax.set_xlabel('Time (s)')
+        ax.set_title(CH_LABELS[i])
+        ax.set_ylim([-10, 20])
+        ax.legend()
+    plt.show()
+
+
+if __name__ == '__main__':
+    main()
diff --git a/examples/p300_demo/analysis_csv.py b/examples/p300_demo/analysis_csv_8_channel.py
similarity index 100%
rename from examples/p300_demo/analysis_csv.py
rename to examples/p300_demo/analysis_csv_8_channel.py
diff --git a/examples/ssvep_demo/TFR.jpeg b/examples/ssvep_demo/TFR.jpeg
index 6ce08a53..aacb892e 100644
Binary files a/examples/ssvep_demo/TFR.jpeg and b/examples/ssvep_demo/TFR.jpeg differ
diff --git a/installer/windows/installer.cfg b/installer/windows/installer.cfg
index 39c27b05..8aa25de3 100644
--- a/installer/windows/installer.cfg
+++ b/installer/windows/installer.cfg
@@ -1,6 +1,6 @@
 [Application]
 name=MentaLab ExplorePy
-version=1.6.0
+version=1.6.1
 entry_point=explorepy.cli:cli
 console=true
 icon=mentalab.ico
@@ -16,7 +16,7 @@ entry_point=explorepy.cli:cli
 
 [Include]
 pypi_wheels =
-    explorepy==1.6.0
+    explorepy==1.6.1
     appdirs==1.4.3
 #   bokeh==2.2.3 # No wheel available
     certifi==2020.12.5
diff --git a/lib/linux/DeviceINQ.cpp b/lib/linux/DeviceINQ.cpp
index 235961af..a72558b8 100644
--- a/lib/linux/DeviceINQ.cpp
+++ b/lib/linux/DeviceINQ.cpp
@@ -48,7 +48,7 @@ vector<device> ExploreSDK::PerformDeviceSearch(int length)
 	int sock = hci_open_dev(dev_id);
 
 	if (dev_id < 0 || sock < 0)
-		throw ExploreException("error opening socket");
+		throw ExploreException("Bluetooth is off. Please turn Bluetooth service on in your machine");
 
 	int max_rsp = 255;
 	inquiry_info *ii = (inquiry_info*)malloc(max_rsp * sizeof(inquiry_info));
diff --git a/lib/linux/ExploreException.h b/lib/linux/ExploreException.h
index d05982f1..db66b8c2 100644
--- a/lib/linux/ExploreException.h
+++ b/lib/linux/ExploreException.h
@@ -45,6 +45,26 @@ class ExploreReadBufferException : std::exception
 	}
 };
 
+// exception for unresponsive socket error
+class ExploreBtSocketException : std::exception
+{
+private:
+	std::string message;
+public:
+	ExploreBtSocketException(std::string message) NOEXCEPT
+	{
+		this->message = message;
+
+	}
+
+
+	virtual const char* what() const NOEXCEPT
+	{
+		return message.c_str();
+	}
+
+};
+
 // class to throw exception when socket is closed but read() method is called from Python
 class ExploreIOException : std::exception
 {
diff --git a/lib/linux/exploresdk.py b/lib/linux/exploresdk.py
index 346ab32a..10677307 100644
--- a/lib/linux/exploresdk.py
+++ b/lib/linux/exploresdk.py
@@ -290,6 +290,20 @@ def what(self) -> "char const *":
 # Register ExploreReadBufferException in _exploresdk:
 _exploresdk.ExploreReadBufferException_swigregister(ExploreReadBufferException)
 
+class ExploreBtSocketException(object):
+    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
+    __repr__ = _swig_repr
+
+    def __init__(self, message: "std::string"):
+        _exploresdk.ExploreBtSocketException_swiginit(self, _exploresdk.new_ExploreBtSocketException(message))
+
+    def what(self) -> "char const *":
+        return _exploresdk.ExploreBtSocketException_what(self)
+    __swig_destroy__ = _exploresdk.delete_ExploreBtSocketException
+
+# Register ExploreBtSocketException in _exploresdk:
+_exploresdk.ExploreBtSocketException_swigregister(ExploreBtSocketException)
+
 class ExploreIOException(object):
     thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
     __repr__ = _swig_repr
diff --git a/lib/linux/swig_interface.i b/lib/linux/swig_interface.i
index 41059a4d..94bec19c 100644
--- a/lib/linux/swig_interface.i
+++ b/lib/linux/swig_interface.i
@@ -20,6 +20,9 @@
     catch(const ExploreIOException& e) {
         SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+        SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
         SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
diff --git a/lib/linux/swig_interface_wrap.cxx b/lib/linux/swig_interface_wrap.cxx
index 663843c8..83032b36 100644
--- a/lib/linux/swig_interface_wrap.cxx
+++ b/lib/linux/swig_interface_wrap.cxx
@@ -2663,26 +2663,27 @@ SWIGINTERN PyObject *SWIG_PyStaticMethod_New(PyObject *SWIGUNUSEDPARM(self), PyO
 /* -------- TYPES TABLE (BEGIN) -------- */
 
 #define SWIGTYPE_p_BTSerialPortBinding swig_types[0]
-#define SWIGTYPE_p_ExploreException swig_types[1]
-#define SWIGTYPE_p_ExploreIOException swig_types[2]
-#define SWIGTYPE_p_ExploreReadBufferException swig_types[3]
-#define SWIGTYPE_p_ExploreSDK swig_types[4]
-#define SWIGTYPE_p_allocator_type swig_types[5]
-#define SWIGTYPE_p_char swig_types[6]
-#define SWIGTYPE_p_device swig_types[7]
-#define SWIGTYPE_p_difference_type swig_types[8]
-#define SWIGTYPE_p_int swig_types[9]
-#define SWIGTYPE_p_p_PyObject swig_types[10]
-#define SWIGTYPE_p_size_type swig_types[11]
-#define SWIGTYPE_p_std__allocatorT_device_t swig_types[12]
-#define SWIGTYPE_p_std__exception swig_types[13]
-#define SWIGTYPE_p_std__invalid_argument swig_types[14]
-#define SWIGTYPE_p_std__time_t swig_types[15]
-#define SWIGTYPE_p_std__vectorT_device_std__allocatorT_device_t_t swig_types[16]
-#define SWIGTYPE_p_swig__SwigPyIterator swig_types[17]
-#define SWIGTYPE_p_value_type swig_types[18]
-static swig_type_info *swig_types[20];
-static swig_module_info swig_module = {swig_types, 19, 0, 0, 0, 0};
+#define SWIGTYPE_p_ExploreBtSocketException swig_types[1]
+#define SWIGTYPE_p_ExploreException swig_types[2]
+#define SWIGTYPE_p_ExploreIOException swig_types[3]
+#define SWIGTYPE_p_ExploreReadBufferException swig_types[4]
+#define SWIGTYPE_p_ExploreSDK swig_types[5]
+#define SWIGTYPE_p_allocator_type swig_types[6]
+#define SWIGTYPE_p_char swig_types[7]
+#define SWIGTYPE_p_device swig_types[8]
+#define SWIGTYPE_p_difference_type swig_types[9]
+#define SWIGTYPE_p_int swig_types[10]
+#define SWIGTYPE_p_p_PyObject swig_types[11]
+#define SWIGTYPE_p_size_type swig_types[12]
+#define SWIGTYPE_p_std__allocatorT_device_t swig_types[13]
+#define SWIGTYPE_p_std__exception swig_types[14]
+#define SWIGTYPE_p_std__invalid_argument swig_types[15]
+#define SWIGTYPE_p_std__time_t swig_types[16]
+#define SWIGTYPE_p_std__vectorT_device_std__allocatorT_device_t_t swig_types[17]
+#define SWIGTYPE_p_swig__SwigPyIterator swig_types[18]
+#define SWIGTYPE_p_value_type swig_types[19]
+static swig_type_info *swig_types[21];
+static swig_module_info swig_module = {swig_types, 20, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -5831,6 +5832,9 @@ SWIGINTERN PyObject *_wrap_delete_BTSerialPortBinding(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -5884,6 +5888,9 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Create(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -5928,6 +5935,9 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Connect(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -5971,6 +5981,9 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Close(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6027,6 +6040,9 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Read(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6079,6 +6095,9 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Write(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6123,6 +6142,9 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_IsDataAvailable(PyObject *SWIGUNU
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6176,6 +6198,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_iterator(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6220,6 +6245,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___nonzero__(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6264,6 +6292,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___bool__(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6308,6 +6339,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___len__(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6373,6 +6407,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___getslice__(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6436,6 +6473,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___setslice____SWIG_0(PyObject *SWIGUNUSE
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6512,6 +6552,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___setslice____SWIG_1(PyObject *SWIGUNUSE
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6640,6 +6683,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___delslice__(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6695,6 +6741,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___delitem____SWIG_0(PyObject *SWIGUNUSED
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6750,6 +6799,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___getitem____SWIG_0(PyObject *SWIGUNUSED
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6817,6 +6869,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___setitem____SWIG_0(PyObject *SWIGUNUSED
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6873,6 +6928,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___setitem____SWIG_1(PyObject *SWIGUNUSED
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6927,6 +6985,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___delitem____SWIG_1(PyObject *SWIGUNUSED
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7026,6 +7087,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___getitem____SWIG_1(PyObject *SWIGUNUSED
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7136,6 +7200,9 @@ SWIGINTERN PyObject *_wrap_vectordevice___setitem____SWIG_2(PyObject *SWIGUNUSED
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7251,6 +7318,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_pop(PyObject *SWIGUNUSEDPARM(self), PyOb
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7304,6 +7374,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_append(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7338,6 +7411,9 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_0(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7385,6 +7461,9 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_1(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7431,6 +7510,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_empty(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7475,6 +7557,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_size(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7528,6 +7613,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_swap(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7572,6 +7660,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_begin(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7617,6 +7708,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_end(PyObject *SWIGUNUSEDPARM(self), PyOb
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7662,6 +7756,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_rbegin(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7707,6 +7804,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_rend(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7751,6 +7851,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_clear(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7795,6 +7898,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_get_allocator(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7837,6 +7943,9 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_2(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7880,6 +7989,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_pop_back(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7929,6 +8041,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_resize__SWIG_0(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7985,6 +8100,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_erase__SWIG_0(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8056,6 +8174,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_erase__SWIG_1(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8159,6 +8280,9 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_3(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8267,6 +8391,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_push_back(PyObject *SWIGUNUSEDPARM(self)
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8311,6 +8438,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_front(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8356,6 +8486,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_back(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8418,6 +8551,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_assign(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8478,6 +8614,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_resize__SWIG_1(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8595,6 +8734,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_insert__SWIG_0(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8670,6 +8812,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_insert__SWIG_1(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8778,6 +8923,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_reserve(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8822,6 +8970,9 @@ SWIGINTERN PyObject *_wrap_vectordevice_capacity(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8865,6 +9016,9 @@ SWIGINTERN PyObject *_wrap_delete_vectordevice(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8922,6 +9076,9 @@ SWIGINTERN PyObject *_wrap_new_ExploreException(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8966,6 +9123,9 @@ SWIGINTERN PyObject *_wrap_ExploreException_what(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9009,6 +9169,9 @@ SWIGINTERN PyObject *_wrap_delete_ExploreException(PyObject *SWIGUNUSEDPARM(self
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9066,6 +9229,9 @@ SWIGINTERN PyObject *_wrap_new_ExploreReadBufferException(PyObject *SWIGUNUSEDPA
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9110,6 +9276,9 @@ SWIGINTERN PyObject *_wrap_ExploreReadBufferException_what(PyObject *SWIGUNUSEDP
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9153,6 +9322,9 @@ SWIGINTERN PyObject *_wrap_delete_ExploreReadBufferException(PyObject *SWIGUNUSE
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9177,6 +9349,159 @@ SWIGINTERN PyObject *ExploreReadBufferException_swiginit(PyObject *SWIGUNUSEDPAR
   return SWIG_Python_InitShadowInstance(args);
 }
 
+SWIGINTERN PyObject *_wrap_new_ExploreBtSocketException(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  std::string arg1 ;
+  PyObject *swig_obj[1] ;
+  ExploreBtSocketException *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  {
+    std::string *ptr = (std::string *)0;
+    int res = SWIG_AsPtr_std_string(swig_obj[0], &ptr);
+    if (!SWIG_IsOK(res) || !ptr) {
+      SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in method '" "new_ExploreBtSocketException" "', argument " "1"" of type '" "std::string""'"); 
+    }
+    arg1 = *ptr;
+    if (SWIG_IsNewObj(res)) delete ptr;
+  }
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        result = (ExploreBtSocketException *)new ExploreBtSocketException(arg1);
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ExploreBtSocketException, SWIG_POINTER_NEW |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_ExploreBtSocketException_what(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ExploreBtSocketException *arg1 = (ExploreBtSocketException *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  char *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ExploreBtSocketException, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ExploreBtSocketException_what" "', argument " "1"" of type '" "ExploreBtSocketException const *""'"); 
+  }
+  arg1 = reinterpret_cast< ExploreBtSocketException * >(argp1);
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        result = (char *)((ExploreBtSocketException const *)arg1)->what();
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_delete_ExploreBtSocketException(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ExploreBtSocketException *arg1 = (ExploreBtSocketException *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ExploreBtSocketException, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_ExploreBtSocketException" "', argument " "1"" of type '" "ExploreBtSocketException *""'"); 
+  }
+  arg1 = reinterpret_cast< ExploreBtSocketException * >(argp1);
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        delete arg1;
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *ExploreBtSocketException_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_ExploreBtSocketException, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *ExploreBtSocketException_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  return SWIG_Python_InitShadowInstance(args);
+}
+
 SWIGINTERN PyObject *_wrap_new_ExploreIOException(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   std::string arg1 ;
@@ -9210,6 +9535,9 @@ SWIGINTERN PyObject *_wrap_new_ExploreIOException(PyObject *SWIGUNUSEDPARM(self)
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9254,6 +9582,9 @@ SWIGINTERN PyObject *_wrap_ExploreIOException_what(PyObject *SWIGUNUSEDPARM(self
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9297,6 +9628,9 @@ SWIGINTERN PyObject *_wrap_delete_ExploreIOException(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9792,6 +10126,9 @@ SWIGINTERN PyObject *_wrap_new_device(PyObject *SWIGUNUSEDPARM(self), PyObject *
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9835,6 +10172,9 @@ SWIGINTERN PyObject *_wrap_delete_device(PyObject *SWIGUNUSEDPARM(self), PyObjec
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9889,6 +10229,9 @@ SWIGINTERN PyObject *_wrap_delete_ExploreSDK(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9923,6 +10266,9 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_Create(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9973,6 +10319,9 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_PerformDeviceSearch__SWIG_0(PyObject *SWIG
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -10015,6 +10364,9 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_PerformDeviceSearch__SWIG_1(PyObject *SWIG
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -10110,6 +10462,9 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_SdpSearch(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -10203,6 +10558,11 @@ static PyMethodDef SwigMethods[] = {
 	 { "delete_ExploreReadBufferException", _wrap_delete_ExploreReadBufferException, METH_O, NULL},
 	 { "ExploreReadBufferException_swigregister", ExploreReadBufferException_swigregister, METH_O, NULL},
 	 { "ExploreReadBufferException_swiginit", ExploreReadBufferException_swiginit, METH_VARARGS, NULL},
+	 { "new_ExploreBtSocketException", _wrap_new_ExploreBtSocketException, METH_O, NULL},
+	 { "ExploreBtSocketException_what", _wrap_ExploreBtSocketException_what, METH_O, NULL},
+	 { "delete_ExploreBtSocketException", _wrap_delete_ExploreBtSocketException, METH_O, NULL},
+	 { "ExploreBtSocketException_swigregister", ExploreBtSocketException_swigregister, METH_O, NULL},
+	 { "ExploreBtSocketException_swiginit", ExploreBtSocketException_swiginit, METH_VARARGS, NULL},
 	 { "new_ExploreIOException", _wrap_new_ExploreIOException, METH_O, NULL},
 	 { "ExploreIOException_what", _wrap_ExploreIOException_what, METH_O, NULL},
 	 { "delete_ExploreIOException", _wrap_delete_ExploreIOException, METH_O, NULL},
@@ -10247,10 +10607,14 @@ static void *_p_ExploreExceptionTo_p_std__exception(void *x, int *SWIGUNUSEDPARM
 static void *_p_ExploreReadBufferExceptionTo_p_std__exception(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((std::exception *)  ((ExploreReadBufferException *) x));
 }
+static void *_p_ExploreBtSocketExceptionTo_p_std__exception(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((std::exception *)  ((ExploreBtSocketException *) x));
+}
 static void *_p_ExploreIOExceptionTo_p_std__exception(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((std::exception *)  ((ExploreIOException *) x));
 }
 static swig_type_info _swigt__p_BTSerialPortBinding = {"_p_BTSerialPortBinding", "BTSerialPortBinding *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_ExploreBtSocketException = {"_p_ExploreBtSocketException", "ExploreBtSocketException *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ExploreException = {"_p_ExploreException", "ExploreException *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ExploreIOException = {"_p_ExploreIOException", "ExploreIOException *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ExploreReadBufferException = {"_p_ExploreReadBufferException", "ExploreReadBufferException *", 0, 0, (void*)0, 0};
@@ -10272,6 +10636,7 @@ static swig_type_info _swigt__p_value_type = {"_p_value_type", "value_type *", 0
 
 static swig_type_info *swig_type_initial[] = {
   &_swigt__p_BTSerialPortBinding,
+  &_swigt__p_ExploreBtSocketException,
   &_swigt__p_ExploreException,
   &_swigt__p_ExploreIOException,
   &_swigt__p_ExploreReadBufferException,
@@ -10293,6 +10658,7 @@ static swig_type_info *swig_type_initial[] = {
 };
 
 static swig_cast_info _swigc__p_BTSerialPortBinding[] = {  {&_swigt__p_BTSerialPortBinding, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_ExploreBtSocketException[] = {  {&_swigt__p_ExploreBtSocketException, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ExploreException[] = {  {&_swigt__p_ExploreException, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ExploreIOException[] = {  {&_swigt__p_ExploreIOException, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ExploreReadBufferException[] = {  {&_swigt__p_ExploreReadBufferException, 0, 0, 0},{0, 0, 0, 0}};
@@ -10305,7 +10671,7 @@ static swig_cast_info _swigc__p_int[] = {  {&_swigt__p_int, 0, 0, 0},{0, 0, 0, 0
 static swig_cast_info _swigc__p_p_PyObject[] = {  {&_swigt__p_p_PyObject, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_size_type[] = {  {&_swigt__p_size_type, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__allocatorT_device_t[] = {  {&_swigt__p_std__allocatorT_device_t, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_std__exception[] = {  {&_swigt__p_std__exception, 0, 0, 0},  {&_swigt__p_ExploreException, _p_ExploreExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreReadBufferException, _p_ExploreReadBufferExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreIOException, _p_ExploreIOExceptionTo_p_std__exception, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_std__exception[] = {  {&_swigt__p_std__exception, 0, 0, 0},  {&_swigt__p_ExploreException, _p_ExploreExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreReadBufferException, _p_ExploreReadBufferExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreBtSocketException, _p_ExploreBtSocketExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreIOException, _p_ExploreIOExceptionTo_p_std__exception, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__invalid_argument[] = {  {&_swigt__p_std__invalid_argument, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__time_t[] = {  {&_swigt__p_std__time_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_device_std__allocatorT_device_t_t[] = {  {&_swigt__p_std__vectorT_device_std__allocatorT_device_t_t, 0, 0, 0},{0, 0, 0, 0}};
@@ -10314,6 +10680,7 @@ static swig_cast_info _swigc__p_value_type[] = {  {&_swigt__p_value_type, 0, 0,
 
 static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_BTSerialPortBinding,
+  _swigc__p_ExploreBtSocketException,
   _swigc__p_ExploreException,
   _swigc__p_ExploreIOException,
   _swigc__p_ExploreReadBufferException,
diff --git a/lib/mac/ExploreException.h b/lib/mac/ExploreException.h
index 9ddfc997..1467d746 100644
--- a/lib/mac/ExploreException.h
+++ b/lib/mac/ExploreException.h
@@ -65,3 +65,23 @@ class ExploreIOException : std::exception
 
 };
 
+
+// exception for unresponsive socket error
+class ExploreBtSocketException : std::exception
+{
+private:
+	std::string message;
+public:
+	ExploreBtSocketException(std::string message) NOEXCEPT
+	{
+		this->message = message;
+
+	}
+
+
+	virtual const char* what() const NOEXCEPT
+	{
+		return message.c_str();
+	}
+
+};
diff --git a/lib/mac/swig_interface.i b/lib/mac/swig_interface.i
index 27e924a3..c482609f 100644
--- a/lib/mac/swig_interface.i
+++ b/lib/mac/swig_interface.i
@@ -20,6 +20,9 @@
     catch(const ExploreIOException& e) {
         SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreBtSocketException& e) {
+        SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
         SWIG_exception(SWIG_UnknownError, "Standard exception");
     } 
diff --git a/lib/windows/BTSerialPortBinding.cpp b/lib/windows/BTSerialPortBinding.cpp
index 84577f14..8870b411 100644
--- a/lib/windows/BTSerialPortBinding.cpp
+++ b/lib/windows/BTSerialPortBinding.cpp
@@ -88,7 +88,13 @@ int BTSerialPortBinding::Connect()
 			}
 			else
 			{
-				cout << "BT Socket error occurred with error message is:" << BluetoothHelpers::GetWSAErrorMessage(WSAGetLastError()) << endl;
+				int lastErrorCode = WSAGetLastError();
+				// Checking if the error is due to bluetooth socket unresponsiveness
+				int btSocketErrorCode = 10058; 
+				cout << "BT Socket error:" << BluetoothHelpers::GetWSAErrorMessage(lastErrorCode) << endl;
+				if(lastErrorCode == btSocketErrorCode) 
+					throw ExploreBtSocketException("Connection attempt not sucessful due to socket error");
+
 			}
 		}
 	}
diff --git a/lib/windows/DeviceINQ.cpp b/lib/windows/DeviceINQ.cpp
index 102dc795..dcacf904 100644
--- a/lib/windows/DeviceINQ.cpp
+++ b/lib/windows/DeviceINQ.cpp
@@ -4,7 +4,7 @@
 
 #define _WINSOCK_DEPRECATED_NO_WARNINGS
 #define _CRT_SECURE_NO_WARNINGS
-
+#include<iostream>
 #include <initguid.h>
 #include <winsock2.h>
 #include <windows.h>
@@ -70,6 +70,10 @@ ExploreSDK::~ExploreSDK()
 
 vector<device> ExploreSDK::PerformDeviceSearch(int length)
 {
+
+	if(!BluetoothIsConnectable(NULL)) 
+		throw ExploreNoBluetoothException("Bluetooth is off. Please turn Bluetooth service on in your machine");
+	
   (void)(length);
 	// Construct windows socket bluetooth variables
 	DWORD flags = LUP_CONTAINERS | LUP_FLUSHCACHE | LUP_RETURN_NAME | LUP_RETURN_ADDR;
diff --git a/lib/windows/ExploreException.h b/lib/windows/ExploreException.h
index f949fecb..50f63698 100644
--- a/lib/windows/ExploreException.h
+++ b/lib/windows/ExploreException.h
@@ -68,4 +68,41 @@ class ExploreIOException : std::exception
 
 };
 
+// exception for unresponsive socket error
+class ExploreBtSocketException : std::exception
+{
+private:
+	std::string message;
+public:
+	ExploreBtSocketException(std::string message) NOEXCEPT
+	{
+		this->message = message;
+
+	}
+
+
+	virtual const char* what() const NOEXCEPT
+	{
+		return message.c_str();
+	}
+
+};
 
+// class to throw exception when no BT service is available
+class ExploreNoBluetoothException : std::exception
+{
+private:
+	std::string message;
+public:
+	ExploreNoBluetoothException(std::string message) NOEXCEPT
+	{
+		this->message = message;
+
+	}
+
+	virtual const char* what() const NOEXCEPT
+	{
+		return message.c_str();
+	}
+
+};
diff --git a/lib/windows/exploresdk.py b/lib/windows/exploresdk.py
index 346ab32a..e13c341c 100644
--- a/lib/windows/exploresdk.py
+++ b/lib/windows/exploresdk.py
@@ -304,6 +304,34 @@ def what(self) -> "char const *":
 # Register ExploreIOException in _exploresdk:
 _exploresdk.ExploreIOException_swigregister(ExploreIOException)
 
+class ExploreBtSocketException(object):
+    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
+    __repr__ = _swig_repr
+
+    def __init__(self, message: "std::string"):
+        _exploresdk.ExploreBtSocketException_swiginit(self, _exploresdk.new_ExploreBtSocketException(message))
+
+    def what(self) -> "char const *":
+        return _exploresdk.ExploreBtSocketException_what(self)
+    __swig_destroy__ = _exploresdk.delete_ExploreBtSocketException
+
+# Register ExploreBtSocketException in _exploresdk:
+_exploresdk.ExploreBtSocketException_swigregister(ExploreBtSocketException)
+
+class ExploreNoBluetoothException(object):
+    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
+    __repr__ = _swig_repr
+
+    def __init__(self, message: "std::string"):
+        _exploresdk.ExploreNoBluetoothException_swiginit(self, _exploresdk.new_ExploreNoBluetoothException(message))
+
+    def what(self) -> "char const *":
+        return _exploresdk.ExploreNoBluetoothException_what(self)
+    __swig_destroy__ = _exploresdk.delete_ExploreNoBluetoothException
+
+# Register ExploreNoBluetoothException in _exploresdk:
+_exploresdk.ExploreNoBluetoothException_swigregister(ExploreNoBluetoothException)
+
 class device(object):
     thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
     __repr__ = _swig_repr
diff --git a/lib/windows/swig_interface.i b/lib/windows/swig_interface.i
index 346a092f..a24c7ce6 100644
--- a/lib/windows/swig_interface.i
+++ b/lib/windows/swig_interface.i
@@ -18,10 +18,15 @@
     catch(const ExploreReadBufferException& e) {
         SWIG_exception(SWIG_MemoryError, e.what());
     }
-	
 	catch(const ExploreIOException& e) {
         SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+        SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+        SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
         SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
diff --git a/lib/windows/swig_interface_wrap.cxx b/lib/windows/swig_interface_wrap.cxx
index 77c8bf6f..4f25098f 100644
--- a/lib/windows/swig_interface_wrap.cxx
+++ b/lib/windows/swig_interface_wrap.cxx
@@ -2663,39 +2663,41 @@ SWIGINTERN PyObject *SWIG_PyStaticMethod_New(PyObject *SWIGUNUSEDPARM(self), PyO
 /* -------- TYPES TABLE (BEGIN) -------- */
 
 #define SWIGTYPE_p_BTSerialPortBinding swig_types[0]
-#define SWIGTYPE_p_ExploreException swig_types[1]
-#define SWIGTYPE_p_ExploreIOException swig_types[2]
-#define SWIGTYPE_p_ExploreReadBufferException swig_types[3]
-#define SWIGTYPE_p_ExploreSDK swig_types[4]
-#define SWIGTYPE_p___int64 swig_types[5]
-#define SWIGTYPE_p_allocator_type swig_types[6]
-#define SWIGTYPE_p_char swig_types[7]
-#define SWIGTYPE_p_device swig_types[8]
-#define SWIGTYPE_p_difference_type swig_types[9]
-#define SWIGTYPE_p_float swig_types[10]
-#define SWIGTYPE_p_int swig_types[11]
-#define SWIGTYPE_p_long swig_types[12]
-#define SWIGTYPE_p_p_PyObject swig_types[13]
-#define SWIGTYPE_p_p_char swig_types[14]
-#define SWIGTYPE_p_p_unsigned_long swig_types[15]
-#define SWIGTYPE_p_short swig_types[16]
-#define SWIGTYPE_p_signed___int64 swig_types[17]
-#define SWIGTYPE_p_signed_char swig_types[18]
-#define SWIGTYPE_p_size_type swig_types[19]
-#define SWIGTYPE_p_std__allocatorT_device_t swig_types[20]
-#define SWIGTYPE_p_std__exception swig_types[21]
-#define SWIGTYPE_p_std__invalid_argument swig_types[22]
-#define SWIGTYPE_p_std__time_t swig_types[23]
-#define SWIGTYPE_p_std__vectorT_device_std__allocatorT_device_t_t swig_types[24]
-#define SWIGTYPE_p_swig__SwigPyIterator swig_types[25]
-#define SWIGTYPE_p_unsigned___int64 swig_types[26]
-#define SWIGTYPE_p_unsigned_char swig_types[27]
-#define SWIGTYPE_p_unsigned_int swig_types[28]
-#define SWIGTYPE_p_unsigned_long swig_types[29]
-#define SWIGTYPE_p_unsigned_short swig_types[30]
-#define SWIGTYPE_p_value_type swig_types[31]
-static swig_type_info *swig_types[33];
-static swig_module_info swig_module = {swig_types, 32, 0, 0, 0, 0};
+#define SWIGTYPE_p_ExploreBtSocketException swig_types[1]
+#define SWIGTYPE_p_ExploreException swig_types[2]
+#define SWIGTYPE_p_ExploreIOException swig_types[3]
+#define SWIGTYPE_p_ExploreNoBluetoothException swig_types[4]
+#define SWIGTYPE_p_ExploreReadBufferException swig_types[5]
+#define SWIGTYPE_p_ExploreSDK swig_types[6]
+#define SWIGTYPE_p___int64 swig_types[7]
+#define SWIGTYPE_p_allocator_type swig_types[8]
+#define SWIGTYPE_p_char swig_types[9]
+#define SWIGTYPE_p_device swig_types[10]
+#define SWIGTYPE_p_difference_type swig_types[11]
+#define SWIGTYPE_p_float swig_types[12]
+#define SWIGTYPE_p_int swig_types[13]
+#define SWIGTYPE_p_long swig_types[14]
+#define SWIGTYPE_p_p_PyObject swig_types[15]
+#define SWIGTYPE_p_p_char swig_types[16]
+#define SWIGTYPE_p_p_unsigned_long swig_types[17]
+#define SWIGTYPE_p_short swig_types[18]
+#define SWIGTYPE_p_signed___int64 swig_types[19]
+#define SWIGTYPE_p_signed_char swig_types[20]
+#define SWIGTYPE_p_size_type swig_types[21]
+#define SWIGTYPE_p_std__allocatorT_device_t swig_types[22]
+#define SWIGTYPE_p_std__exception swig_types[23]
+#define SWIGTYPE_p_std__invalid_argument swig_types[24]
+#define SWIGTYPE_p_std__time_t swig_types[25]
+#define SWIGTYPE_p_std__vectorT_device_std__allocatorT_device_t_t swig_types[26]
+#define SWIGTYPE_p_swig__SwigPyIterator swig_types[27]
+#define SWIGTYPE_p_unsigned___int64 swig_types[28]
+#define SWIGTYPE_p_unsigned_char swig_types[29]
+#define SWIGTYPE_p_unsigned_int swig_types[30]
+#define SWIGTYPE_p_unsigned_long swig_types[31]
+#define SWIGTYPE_p_unsigned_short swig_types[32]
+#define SWIGTYPE_p_value_type swig_types[33]
+static swig_type_info *swig_types[35];
+static swig_module_info swig_module = {swig_types, 34, 0, 0, 0, 0};
 #define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)
 #define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)
 
@@ -5844,10 +5846,15 @@ SWIGINTERN PyObject *_wrap_delete_BTSerialPortBinding(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -5898,10 +5905,15 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Create(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -5943,10 +5955,15 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Connect(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -5987,10 +6004,15 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Close(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6044,10 +6066,15 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Read(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6097,10 +6124,15 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_Write(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6142,10 +6174,15 @@ SWIGINTERN PyObject *_wrap_BTSerialPortBinding_IsDataAvailable(PyObject *SWIGUNU
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6196,10 +6233,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_iterator(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6241,10 +6283,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___nonzero__(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6286,10 +6333,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___bool__(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6331,10 +6383,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___len__(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6397,10 +6454,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___getslice__(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6461,10 +6523,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___setslice____SWIG_0(PyObject *SWIGUNUSE
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6538,10 +6605,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___setslice____SWIG_1(PyObject *SWIGUNUSE
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6667,10 +6739,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___delslice__(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6723,10 +6800,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___delitem____SWIG_0(PyObject *SWIGUNUSED
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6779,10 +6861,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___getitem____SWIG_0(PyObject *SWIGUNUSED
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6847,10 +6934,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___setitem____SWIG_0(PyObject *SWIGUNUSED
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6904,10 +6996,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___setitem____SWIG_1(PyObject *SWIGUNUSED
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -6959,10 +7056,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___delitem____SWIG_1(PyObject *SWIGUNUSED
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7059,10 +7161,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___getitem____SWIG_1(PyObject *SWIGUNUSED
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7170,10 +7277,15 @@ SWIGINTERN PyObject *_wrap_vectordevice___setitem____SWIG_2(PyObject *SWIGUNUSED
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7286,10 +7398,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_pop(PyObject *SWIGUNUSEDPARM(self), PyOb
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7340,10 +7457,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_append(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7375,10 +7497,15 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_0(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7423,10 +7550,15 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_1(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7470,10 +7602,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_empty(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7515,10 +7652,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_size(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7569,10 +7711,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_swap(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7614,10 +7761,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_begin(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7660,10 +7812,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_end(PyObject *SWIGUNUSEDPARM(self), PyOb
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7706,10 +7863,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_rbegin(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7752,10 +7914,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_rend(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7797,10 +7964,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_clear(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7842,10 +8014,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_get_allocator(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7885,10 +8062,15 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_2(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7929,10 +8111,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_pop_back(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -7979,10 +8166,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_resize__SWIG_0(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8036,10 +8228,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_erase__SWIG_0(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8108,10 +8305,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_erase__SWIG_1(PyObject *SWIGUNUSEDPARM(s
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8212,10 +8414,15 @@ SWIGINTERN PyObject *_wrap_new_vectordevice__SWIG_3(PyObject *SWIGUNUSEDPARM(sel
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8321,10 +8528,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_push_back(PyObject *SWIGUNUSEDPARM(self)
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8366,10 +8578,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_front(PyObject *SWIGUNUSEDPARM(self), Py
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8412,10 +8629,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_back(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8475,10 +8697,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_assign(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8536,10 +8763,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_resize__SWIG_1(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8654,10 +8886,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_insert__SWIG_0(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8730,10 +8967,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_insert__SWIG_1(PyObject *SWIGUNUSEDPARM(
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8839,10 +9081,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_reserve(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8884,10 +9131,15 @@ SWIGINTERN PyObject *_wrap_vectordevice_capacity(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8928,10 +9180,15 @@ SWIGINTERN PyObject *_wrap_delete_vectordevice(PyObject *SWIGUNUSEDPARM(self), P
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -8986,10 +9243,15 @@ SWIGINTERN PyObject *_wrap_new_ExploreException(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9031,10 +9293,15 @@ SWIGINTERN PyObject *_wrap_ExploreException_what(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9075,10 +9342,15 @@ SWIGINTERN PyObject *_wrap_delete_ExploreException(PyObject *SWIGUNUSEDPARM(self
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9133,10 +9405,15 @@ SWIGINTERN PyObject *_wrap_new_ExploreReadBufferException(PyObject *SWIGUNUSEDPA
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9178,10 +9455,15 @@ SWIGINTERN PyObject *_wrap_ExploreReadBufferException_what(PyObject *SWIGUNUSEDP
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9222,10 +9504,15 @@ SWIGINTERN PyObject *_wrap_delete_ExploreReadBufferException(PyObject *SWIGUNUSE
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9280,10 +9567,15 @@ SWIGINTERN PyObject *_wrap_new_ExploreIOException(PyObject *SWIGUNUSEDPARM(self)
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9325,10 +9617,15 @@ SWIGINTERN PyObject *_wrap_ExploreIOException_what(PyObject *SWIGUNUSEDPARM(self
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9369,10 +9666,15 @@ SWIGINTERN PyObject *_wrap_delete_ExploreIOException(PyObject *SWIGUNUSEDPARM(se
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9397,6 +9699,330 @@ SWIGINTERN PyObject *ExploreIOException_swiginit(PyObject *SWIGUNUSEDPARM(self),
   return SWIG_Python_InitShadowInstance(args);
 }
 
+SWIGINTERN PyObject *_wrap_new_ExploreBtSocketException(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  std::string arg1 ;
+  PyObject *swig_obj[1] ;
+  ExploreBtSocketException *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  {
+    std::string *ptr = (std::string *)0;
+    int res = SWIG_AsPtr_std_string(swig_obj[0], &ptr);
+    if (!SWIG_IsOK(res) || !ptr) {
+      SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in method '" "new_ExploreBtSocketException" "', argument " "1"" of type '" "std::string""'"); 
+    }
+    arg1 = *ptr;
+    if (SWIG_IsNewObj(res)) delete ptr;
+  }
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        result = (ExploreBtSocketException *)new ExploreBtSocketException(arg1);
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ExploreBtSocketException, SWIG_POINTER_NEW |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_ExploreBtSocketException_what(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ExploreBtSocketException *arg1 = (ExploreBtSocketException *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  char *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ExploreBtSocketException, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ExploreBtSocketException_what" "', argument " "1"" of type '" "ExploreBtSocketException const *""'"); 
+  }
+  arg1 = reinterpret_cast< ExploreBtSocketException * >(argp1);
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        result = (char *)((ExploreBtSocketException const *)arg1)->what();
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_delete_ExploreBtSocketException(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ExploreBtSocketException *arg1 = (ExploreBtSocketException *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ExploreBtSocketException, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_ExploreBtSocketException" "', argument " "1"" of type '" "ExploreBtSocketException *""'"); 
+  }
+  arg1 = reinterpret_cast< ExploreBtSocketException * >(argp1);
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        delete arg1;
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *ExploreBtSocketException_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_ExploreBtSocketException, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *ExploreBtSocketException_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  return SWIG_Python_InitShadowInstance(args);
+}
+
+SWIGINTERN PyObject *_wrap_new_ExploreNoBluetoothException(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  std::string arg1 ;
+  PyObject *swig_obj[1] ;
+  ExploreNoBluetoothException *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  {
+    std::string *ptr = (std::string *)0;
+    int res = SWIG_AsPtr_std_string(swig_obj[0], &ptr);
+    if (!SWIG_IsOK(res) || !ptr) {
+      SWIG_exception_fail(SWIG_ArgError((ptr ? res : SWIG_TypeError)), "in method '" "new_ExploreNoBluetoothException" "', argument " "1"" of type '" "std::string""'"); 
+    }
+    arg1 = *ptr;
+    if (SWIG_IsNewObj(res)) delete ptr;
+  }
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        result = (ExploreNoBluetoothException *)new ExploreNoBluetoothException(arg1);
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_NewPointerObj(SWIG_as_voidptr(result), SWIGTYPE_p_ExploreNoBluetoothException, SWIG_POINTER_NEW |  0 );
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_ExploreNoBluetoothException_what(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ExploreNoBluetoothException *arg1 = (ExploreNoBluetoothException *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  char *result = 0 ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ExploreNoBluetoothException, 0 |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "ExploreNoBluetoothException_what" "', argument " "1"" of type '" "ExploreNoBluetoothException const *""'"); 
+  }
+  arg1 = reinterpret_cast< ExploreNoBluetoothException * >(argp1);
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        result = (char *)((ExploreNoBluetoothException const *)arg1)->what();
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_FromCharPtr((const char *)result);
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *_wrap_delete_ExploreNoBluetoothException(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *resultobj = 0;
+  ExploreNoBluetoothException *arg1 = (ExploreNoBluetoothException *) 0 ;
+  void *argp1 = 0 ;
+  int res1 = 0 ;
+  PyObject *swig_obj[1] ;
+  
+  if (!args) SWIG_fail;
+  swig_obj[0] = args;
+  res1 = SWIG_ConvertPtr(swig_obj[0], &argp1,SWIGTYPE_p_ExploreNoBluetoothException, SWIG_POINTER_DISOWN |  0 );
+  if (!SWIG_IsOK(res1)) {
+    SWIG_exception_fail(SWIG_ArgError(res1), "in method '" "delete_ExploreNoBluetoothException" "', argument " "1"" of type '" "ExploreNoBluetoothException *""'"); 
+  }
+  arg1 = reinterpret_cast< ExploreNoBluetoothException * >(argp1);
+  {
+    try {
+      {
+        SWIG_PYTHON_THREAD_BEGIN_ALLOW;
+        delete arg1;
+        SWIG_PYTHON_THREAD_END_ALLOW;
+      }
+    } catch(const ExploreException& e) {
+      SWIG_exception(SWIG_ValueError, e.what());
+    }
+    catch(const ExploreReadBufferException& e) {
+      SWIG_exception(SWIG_MemoryError, e.what());
+    }
+    catch(const ExploreIOException& e) {
+      SWIG_exception(SWIG_IOError, e.what());
+    }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
+    catch(const std::exception& e) {
+      SWIG_exception(SWIG_UnknownError, "Standard exception");
+    } catch(...) {
+      SWIG_exception(SWIG_RuntimeError, "Unknown exception");
+    }
+  }
+  resultobj = SWIG_Py_Void();
+  return resultobj;
+fail:
+  return NULL;
+}
+
+
+SWIGINTERN PyObject *ExploreNoBluetoothException_swigregister(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  PyObject *obj;
+  if (!SWIG_Python_UnpackTuple(args, "swigregister", 1, 1, &obj)) return NULL;
+  SWIG_TypeNewClientData(SWIGTYPE_p_ExploreNoBluetoothException, SWIG_NewClientData(obj));
+  return SWIG_Py_Void();
+}
+
+SWIGINTERN PyObject *ExploreNoBluetoothException_swiginit(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
+  return SWIG_Python_InitShadowInstance(args);
+}
+
 SWIGINTERN PyObject *_wrap_device_address_set(PyObject *SWIGUNUSEDPARM(self), PyObject *args) {
   PyObject *resultobj = 0;
   device *arg1 = (device *) 0 ;
@@ -9865,10 +10491,15 @@ SWIGINTERN PyObject *_wrap_new_device(PyObject *SWIGUNUSEDPARM(self), PyObject *
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9909,10 +10540,15 @@ SWIGINTERN PyObject *_wrap_delete_device(PyObject *SWIGUNUSEDPARM(self), PyObjec
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9964,10 +10600,15 @@ SWIGINTERN PyObject *_wrap_delete_ExploreSDK(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -9999,10 +10640,15 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_Create(PyObject *SWIGUNUSEDPARM(self), PyO
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -10050,10 +10696,15 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_PerformDeviceSearch__SWIG_0(PyObject *SWIG
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -10093,10 +10744,15 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_PerformDeviceSearch__SWIG_1(PyObject *SWIG
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -10189,10 +10845,15 @@ SWIGINTERN PyObject *_wrap_ExploreSDK_SdpSearch(PyObject *SWIGUNUSEDPARM(self),
     catch(const ExploreReadBufferException& e) {
       SWIG_exception(SWIG_MemoryError, e.what());
     }
-    
     catch(const ExploreIOException& e) {
       SWIG_exception(SWIG_IOError, e.what());
     }
+    catch(const ExploreNoBluetoothException& e) {
+      SWIG_exception(SWIG_SystemError, e.what());
+    }
+    catch(const ExploreBtSocketException& e) {
+      SWIG_exception(SWIG_TypeError, e.what());
+    }
     catch(const std::exception& e) {
       SWIG_exception(SWIG_UnknownError, "Standard exception");
     } catch(...) {
@@ -10291,6 +10952,16 @@ static PyMethodDef SwigMethods[] = {
 	 { "delete_ExploreIOException", _wrap_delete_ExploreIOException, METH_O, NULL},
 	 { "ExploreIOException_swigregister", ExploreIOException_swigregister, METH_O, NULL},
 	 { "ExploreIOException_swiginit", ExploreIOException_swiginit, METH_VARARGS, NULL},
+	 { "new_ExploreBtSocketException", _wrap_new_ExploreBtSocketException, METH_O, NULL},
+	 { "ExploreBtSocketException_what", _wrap_ExploreBtSocketException_what, METH_O, NULL},
+	 { "delete_ExploreBtSocketException", _wrap_delete_ExploreBtSocketException, METH_O, NULL},
+	 { "ExploreBtSocketException_swigregister", ExploreBtSocketException_swigregister, METH_O, NULL},
+	 { "ExploreBtSocketException_swiginit", ExploreBtSocketException_swiginit, METH_VARARGS, NULL},
+	 { "new_ExploreNoBluetoothException", _wrap_new_ExploreNoBluetoothException, METH_O, NULL},
+	 { "ExploreNoBluetoothException_what", _wrap_ExploreNoBluetoothException_what, METH_O, NULL},
+	 { "delete_ExploreNoBluetoothException", _wrap_delete_ExploreNoBluetoothException, METH_O, NULL},
+	 { "ExploreNoBluetoothException_swigregister", ExploreNoBluetoothException_swigregister, METH_O, NULL},
+	 { "ExploreNoBluetoothException_swiginit", ExploreNoBluetoothException_swiginit, METH_VARARGS, NULL},
 	 { "device_address_set", _wrap_device_address_set, METH_VARARGS, NULL},
 	 { "device_address_get", _wrap_device_address_get, METH_O, NULL},
 	 { "device_name_set", _wrap_device_name_set, METH_VARARGS, NULL},
@@ -10333,9 +11004,17 @@ static void *_p_ExploreReadBufferExceptionTo_p_std__exception(void *x, int *SWIG
 static void *_p_ExploreIOExceptionTo_p_std__exception(void *x, int *SWIGUNUSEDPARM(newmemory)) {
     return (void *)((std::exception *)  ((ExploreIOException *) x));
 }
+static void *_p_ExploreBtSocketExceptionTo_p_std__exception(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((std::exception *)  ((ExploreBtSocketException *) x));
+}
+static void *_p_ExploreNoBluetoothExceptionTo_p_std__exception(void *x, int *SWIGUNUSEDPARM(newmemory)) {
+    return (void *)((std::exception *)  ((ExploreNoBluetoothException *) x));
+}
 static swig_type_info _swigt__p_BTSerialPortBinding = {"_p_BTSerialPortBinding", "BTSerialPortBinding *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_ExploreBtSocketException = {"_p_ExploreBtSocketException", "ExploreBtSocketException *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ExploreException = {"_p_ExploreException", "ExploreException *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ExploreIOException = {"_p_ExploreIOException", "ExploreIOException *", 0, 0, (void*)0, 0};
+static swig_type_info _swigt__p_ExploreNoBluetoothException = {"_p_ExploreNoBluetoothException", "ExploreNoBluetoothException *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ExploreReadBufferException = {"_p_ExploreReadBufferException", "ExploreReadBufferException *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p_ExploreSDK = {"_p_ExploreSDK", "ExploreSDK *", 0, 0, (void*)0, 0};
 static swig_type_info _swigt__p___int64 = {"_p___int64", "__int64 *|LONGLONG *|LONG64 *", 0, 0, (void*)0, 0};
@@ -10368,8 +11047,10 @@ static swig_type_info _swigt__p_value_type = {"_p_value_type", "value_type *", 0
 
 static swig_type_info *swig_type_initial[] = {
   &_swigt__p_BTSerialPortBinding,
+  &_swigt__p_ExploreBtSocketException,
   &_swigt__p_ExploreException,
   &_swigt__p_ExploreIOException,
+  &_swigt__p_ExploreNoBluetoothException,
   &_swigt__p_ExploreReadBufferException,
   &_swigt__p_ExploreSDK,
   &_swigt__p___int64,
@@ -10402,8 +11083,10 @@ static swig_type_info *swig_type_initial[] = {
 };
 
 static swig_cast_info _swigc__p_BTSerialPortBinding[] = {  {&_swigt__p_BTSerialPortBinding, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_ExploreBtSocketException[] = {  {&_swigt__p_ExploreBtSocketException, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ExploreException[] = {  {&_swigt__p_ExploreException, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ExploreIOException[] = {  {&_swigt__p_ExploreIOException, 0, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_ExploreNoBluetoothException[] = {  {&_swigt__p_ExploreNoBluetoothException, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ExploreReadBufferException[] = {  {&_swigt__p_ExploreReadBufferException, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_ExploreSDK[] = {  {&_swigt__p_ExploreSDK, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p___int64[] = {  {&_swigt__p___int64, 0, 0, 0},{0, 0, 0, 0}};
@@ -10422,7 +11105,7 @@ static swig_cast_info _swigc__p_signed___int64[] = {  {&_swigt__p_signed___int64
 static swig_cast_info _swigc__p_signed_char[] = {  {&_swigt__p_signed_char, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_size_type[] = {  {&_swigt__p_size_type, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__allocatorT_device_t[] = {  {&_swigt__p_std__allocatorT_device_t, 0, 0, 0},{0, 0, 0, 0}};
-static swig_cast_info _swigc__p_std__exception[] = {  {&_swigt__p_std__exception, 0, 0, 0},  {&_swigt__p_ExploreException, _p_ExploreExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreReadBufferException, _p_ExploreReadBufferExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreIOException, _p_ExploreIOExceptionTo_p_std__exception, 0, 0},{0, 0, 0, 0}};
+static swig_cast_info _swigc__p_std__exception[] = {  {&_swigt__p_std__exception, 0, 0, 0},  {&_swigt__p_ExploreException, _p_ExploreExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreReadBufferException, _p_ExploreReadBufferExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreIOException, _p_ExploreIOExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreBtSocketException, _p_ExploreBtSocketExceptionTo_p_std__exception, 0, 0},  {&_swigt__p_ExploreNoBluetoothException, _p_ExploreNoBluetoothExceptionTo_p_std__exception, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__invalid_argument[] = {  {&_swigt__p_std__invalid_argument, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__time_t[] = {  {&_swigt__p_std__time_t, 0, 0, 0},{0, 0, 0, 0}};
 static swig_cast_info _swigc__p_std__vectorT_device_std__allocatorT_device_t_t[] = {  {&_swigt__p_std__vectorT_device_std__allocatorT_device_t_t, 0, 0, 0},{0, 0, 0, 0}};
@@ -10436,8 +11119,10 @@ static swig_cast_info _swigc__p_value_type[] = {  {&_swigt__p_value_type, 0, 0,
 
 static swig_cast_info *swig_cast_initial[] = {
   _swigc__p_BTSerialPortBinding,
+  _swigc__p_ExploreBtSocketException,
   _swigc__p_ExploreException,
   _swigc__p_ExploreIOException,
+  _swigc__p_ExploreNoBluetoothException,
   _swigc__p_ExploreReadBufferException,
   _swigc__p_ExploreSDK,
   _swigc__p___int64,
@@ -11209,4 +11894,3 @@ SWIG_init(void) {
   return;
 #endif
 }
-
diff --git a/setup.cfg b/setup.cfg
index 13cf4635..17791872 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -3,30 +3,46 @@ universal = 1
 
 
 [flake8]
-max-line-length = 140
-exclude = */migrations/*
+max-line-length = 120
+ignore = D203, C901
+exclude =
+    .git,
+    __pycache__,
+    old,
+    build,
+    dist,
+    docs,
+    examples,
+    src/explorepy/dashboard/templates,
+    installer,
+    lib,
+    licenses,
+    src/explorepy/exploresdk.py,  # Autogenerated by swig
+# For more info: https://en.wikipedia.org/wiki/Cyclomatic_complexity#Interpretation
+max-complexity = 10
 
-[tool:pytest]
+[tool.pytest]
+minversion = 6.0
+addopts = -ra -q
 testpaths = tests
-norecursedirs =
-    migrations
 
-python_files =
-    test_*.py
-    *_test.py
-    tests.py
-addopts =
-    -ra
-    --strict
-    --doctest-modules
-    --doctest-glob=\*.rst
-    --tb=short
 
 [isort]
-force_single_line = True
 line_length = 120
 known_first_party = explorepy
 default_section = THIRDPARTY
 forced_separate = test_explorepy
-not_skip = __init__.py
-skip = migrations
\ No newline at end of file
+profile=pycharm
+skip=
+    .git,
+    __pycache__,
+    old,
+    build,
+    dist,
+    docs,
+    examples,
+    src/explorepy/dashboard/templates,
+    installer,
+    lib,
+    licenses,
+    src/explorepy/exploresdk.py,  # Autogenerated by swig
diff --git a/setup.py b/setup.py
index c38badb2..544f3bec 100644
--- a/setup.py
+++ b/setup.py
@@ -1,21 +1,27 @@
 #!/usr/bin/env python
 # -*- encoding: utf-8 -*-
-from __future__ import absolute_import
-from __future__ import print_function
+from __future__ import (
+    absolute_import,
+    print_function
+)
 
 import io
-import re
 import os
+import re
 import sys
 from glob import glob
-from os.path import basename
-from os.path import dirname
-from os.path import join
-from os.path import splitext
+from os.path import (
+    basename,
+    dirname,
+    join,
+    splitext
+)
 
-from setuptools import find_packages
-from setuptools import setup
-from setuptools import Extension
+from setuptools import (
+    Extension,
+    find_packages,
+    setup
+)
 
 
 def read(*names, **kwargs):
@@ -26,12 +32,19 @@ def read(*names, **kwargs):
         return fh.read()
 
 
-my_req = ['numpy', 'scipy', 'pyedflib==0.1.22', 'click==7.0', 'appdirs==1.4.3', 'sentry_sdk==1.0.0']
+my_req = ['numpy', 'scipy', 'pyedflib==0.1.25', 'click==7.1.2', 'appdirs==1.4.3', 'sentry_sdk==1.0.0']
+
+test_requirements = ["pytest==6.2.5",
+                     "flake8==4.0.1",
+                     "isort==5.10.1"]
+extras = {"test": test_requirements}
+
 ext_modules_list = []
 current_platform = sys.platform
 
 if not os.environ.get('READTHEDOCS'):
     my_req.append('pylsl')
+    my_req.append('Jinja2==3.0.0')
     my_req.append('bokeh==2.2.3')
     libPath = "lib"
     if current_platform == 'win32' or current_platform == 'win64':
@@ -68,7 +81,7 @@ def read(*names, **kwargs):
         os.system('cp  lib/mac/exploresdk.py  src/explorepy')
 setup(
     name='explorepy',
-    version='1.6.0',
+    version='1.6.1',
     license='MIT license',
     description='Python API for Mentalab biosignal aquisition devices',
     long_description='%s\n%s' % (
@@ -104,7 +117,7 @@ def read(*names, **kwargs):
         'Mentalab', 'Explorepy', 'EEG signal',
     ],
     install_requires=my_req,
-    extras_require={},
+    extras_require=extras,
     entry_points='''
         [console_scripts]
         explorepy=explorepy.cli:cli
diff --git a/src/explorepy/__init__.py b/src/explorepy/__init__.py
index a6cae7ca..c221a3d6 100644
--- a/src/explorepy/__init__.py
+++ b/src/explorepy/__init__.py
@@ -1,20 +1,28 @@
 import logging
 import platform
 import sys
+
 from . import log_config
 
+
+# need to import logger before importing other modules to catch logs during initialization
 logger = logging.getLogger(__name__)
 logger.setLevel(logging.DEBUG)
 logger.debug("NEW SESSION ---------------------------------------------")
 logger.debug("OS: %s - %s ", platform.platform(), sys.version)
 log_config.log_breadcrumb(f"OS: {platform.platform()} - {sys.version}", "info")
 
-from .explore import Explore
-from . import tools, command, exploresdk
-from .dashboard.dashboard import Dashboard
+from . import (  # noqa ignore E402
+    command,
+    exploresdk,
+    tools
+)
+from .dashboard.dashboard import Dashboard  # noqa
+from .explore import Explore  # noqa
 
 
-__version__ = '1.6.0'
+__all__ = ["Explore", "Dashboard", "command", "exploresdk", "tools", "log_config"]
+__version__ = '1.6.1'
 
 this = sys.modules[__name__]
 this._bt_interface = 'sdk'
@@ -47,4 +55,3 @@ def get_bt_interface():
         bt_interface (str): Current Bluetooth interface: 'sdk'
     """
     return this._bt_interface
-
diff --git a/src/explorepy/_exceptions.py b/src/explorepy/_exceptions.py
index 37f1c37c..adf7d88a 100644
--- a/src/explorepy/_exceptions.py
+++ b/src/explorepy/_exceptions.py
@@ -20,6 +20,13 @@ class DeviceNotFoundError(IOError):
     pass
 
 
+class UnsupportedBtHardwareError(Exception):
+    """
+    Exception for Bluetooth hardwares needing manual intervention
+    """
+    pass
+
+
 class FletcherError(Exception):
     """
     Fletcher value error
diff --git a/src/explorepy/btcpp.py b/src/explorepy/btcpp.py
index 559c3801..b20940a7 100644
--- a/src/explorepy/btcpp.py
+++ b/src/explorepy/btcpp.py
@@ -1,10 +1,14 @@
 # -*- coding: utf-8 -*-
 """A module for bluetooth connection"""
-import time
 import logging
+import time
 
 from explorepy import exploresdk
-from explorepy._exceptions import DeviceNotFoundError, InputError
+from explorepy._exceptions import (
+    DeviceNotFoundError,
+    InputError
+)
+
 
 logger = logging.getLogger(__name__)
 
@@ -51,19 +55,30 @@ def connect(self):
                     self.is_connected = False
                     logger.warning("Could not connect; Retrying in 2s...")
                     time.sleep(2)
+
+            except TypeError as error:
+                self.is_connected = False
+                logger.debug(
+                    "Got an exception while connecting to the device: {} of type: {}".format(error, type(error))
+                )
+                raise ConnectionRefusedError("Please unpair Explore device manually or use a Bluetooth dongle")
             except Exception as error:
                 self.is_connected = False
-                logger.debug("Got an exception while connecting to the device: {} of type: {}".format(error, type(error)))
+                logger.debug(
+                    "Got an exception while connecting to the device: {} of type: {}".format(error, type(error))
+                )
                 logger.warning("Could not connect; Retrying in 2s...")
                 time.sleep(2)
 
         self.is_connected = False
-        raise DeviceNotFoundError("Could not find the device! Please make sure the device is on and in advertising mode.")
+        raise DeviceNotFoundError(
+            "Could not find the device! Please make sure the device is on and in advertising mode."
+        )
 
     def reconnect(self):
         """Reconnect to the last used bluetooth socket.
 
-        This function reconnects to the the last bluetooth socket. If after 1 minute the connection doesn't succeed,
+        This function reconnects to the last bluetooth socket. If after 1 minute the connection doesn't succeed,
         program will end.
         """
         self.is_connected = False
@@ -130,7 +145,10 @@ def read(self, n_bytes):
             raise ConnectionAbortedError(str(error))
         except Exception as error:
             print(error)
-            logger.error("unknown error occured while reading bluetooth data by exploresdk")
+            logger.error(
+                "unknown error occured while reading bluetooth data by "
+                "exploresdk {} of type:{}".format(error, type(error))
+            )
 
     def send(self, data):
         """Send data to the device
diff --git a/src/explorepy/cli.py b/src/explorepy/cli.py
index 164e9891..55bd4fe7 100644
--- a/src/explorepy/cli.py
+++ b/src/explorepy/cli.py
@@ -1,11 +1,14 @@
 # -*- coding: utf-8 -*-
 """Command Line Interface module for explorepy"""
+import logging
 import sys
 from functools import update_wrapper
-import logging
+
 import click
+
 import explorepy
 
+
 CONTEXT_SETTINGS = dict(help_option_names=['-h', '--help'])
 logger = logging.getLogger(__name__)
 
@@ -187,7 +190,8 @@ def soft_reset(address, name):
 @click.option("--address", "-a", type=str, help="Explore device's MAC address")
 @click.option("--name", "-n", type=str, help="Name of the device")
 @click.option("-m", "--channel-mask", type=str, required=True,
-              help="Channel mask, it should be a binary string containing 1 and 0, representing the mask (LSB is channel 1).")
+              help="Channel mask, it should be a binary string containing 1 and 0, "
+                   "representing the mask (LSB is channel 1).")
 @verify_inputs
 def set_channels(address, name, channel_mask):
     """Mask the channels of the Explore device"""
@@ -230,4 +234,3 @@ def calibrate_orn(address, name, overwrite):
     explore = explorepy.explore.Explore()
     explore.connect(mac_address=address, device_name=name)
     explore.calibrate_orn(do_overwrite=overwrite)
-
diff --git a/src/explorepy/command.py b/src/explorepy/command.py
index c9335bf1..bb2ea67b 100644
--- a/src/explorepy/command.py
+++ b/src/explorepy/command.py
@@ -2,11 +2,12 @@
 """
 A module providing classes for Explore device configuration
 """
+import abc
+import logging
 import time
 from datetime import datetime
-import abc
 from enum import Enum
-import logging
+
 
 logger = logging.getLogger(__name__)
 
@@ -28,6 +29,7 @@ class OpcodeID(Enum):
     CMD_ZM_DISABLE = b'\xA6'
     CMD_ZM_ENABLE = b'\xA7'
     CMD_SOFT_RESET = b'\xA8'
+    CMD_TEST_SIG = b'\xAA'
 
 
 class Result(Enum):
@@ -61,7 +63,7 @@ def change_setting(self, command):
             command (explorepy.command.Command): Command to be executed
 
         Returns:
-              bool: If the command has been successfully executed.
+              bool: True if the command has been successfully executed.
         """
         self._last_ack_message = None
         self._last_status_message = None
@@ -152,8 +154,9 @@ def __init__(self):
     def translate(self):
         """Translates the command to binary array understandable by Explore device. """
         self.get_time()
-        return self.pid.value + self.cnt + self.payload_length + self.host_ts + self.opcode.value +\
-               self.param + self.fletcher
+        result = [self.pid.value, self.cnt, self.payload_length,
+                  self.host_ts, self.opcode.value, self.param, self.fletcher]
+        return b''.join(result)
 
     def get_time(self):
         """Gets the current machine time based on unix format and fills the corresponding field.
@@ -330,6 +333,25 @@ def __str__(self):
         return "Reset command"
 
 
+class SetChTest(Command2B):
+    """Enable test signal"""
+    def __init__(self, ch_mask):
+        """
+        Args:
+            ch_mask (int): ExG channel mask on which the test signal should be activated.
+                            It should be integers between 1 and 255 (equivalent of binary representation of the mask).
+        """
+        super().__init__()
+        self.opcode = OpcodeID.CMD_TEST_SIG
+        if 0 <= ch_mask <= 255:
+            self.param = bytes([ch_mask])
+        else:
+            raise ValueError("Invalid input")
+
+    def __str__(self):
+        return "Test signal activation command"
+
+
 COMMAND_CLASS_DICT = {
     CommandID.API2BCMD: Command2B,
     CommandID.API4BCMD: Command4B
diff --git a/src/explorepy/dashboard/dashboard.py b/src/explorepy/dashboard/dashboard.py
index 9aec8b42..c736fccc 100644
--- a/src/explorepy/dashboard/dashboard.py
+++ b/src/explorepy/dashboard/dashboard.py
@@ -1,25 +1,51 @@
 # -*- coding: utf-8 -*-
 """Dashboard module"""
+import logging
 import os
-from functools import partial
 from datetime import datetime
-import logging
+from functools import partial
+
 import numpy as np
-from scipy.ndimage import gaussian_filter1d
-from bokeh.layouts import widgetbox, row, column, Spacer
-from bokeh.models import ColumnDataSource, ResetTool, Panel, Tabs, SingleIntervalTicker, widgets, \
-    Toggle, TextInput, RadioGroup, Div, Button, CheckboxGroup, BoxZoomTool
+from bokeh.core.property.validation import (
+    validate,
+    without_property_validation
+)
+from bokeh.layouts import (
+    Spacer,
+    column,
+    row,
+    widgetbox
+)
+from bokeh.models import (
+    BoxZoomTool,
+    Button,
+    CheckboxGroup,
+    ColumnDataSource,
+    Div,
+    Panel,
+    RadioGroup,
+    ResetTool,
+    SingleIntervalTicker,
+    Tabs,
+    TextInput,
+    Toggle,
+    widgets
+)
+from bokeh.palettes import Category20
 from bokeh.plotting import figure
 from bokeh.server.server import Server
-from bokeh.palettes import Category20
-from bokeh.core.property.validation import validate, without_property_validation
-from bokeh.transform import dodge
 from bokeh.themes import Theme
-from tornado import gen
+from bokeh.transform import dodge
 from jinja2 import Template
+from scipy.ndimage import gaussian_filter1d
+from tornado import gen
 
-from explorepy.tools import HeartRateEstimator, find_free_port
 from explorepy.stream_processor import TOPICS
+from explorepy.tools import (
+    HeartRateEstimator,
+    find_free_port
+)
+
 
 logger = logging.getLogger(__name__)
 ORN_SRATE = 20  # Hz
@@ -105,10 +131,10 @@ def __init__(self, explore=None, mode='signal'):
         self.fft_source = ColumnDataSource(data=init_data)
 
         # Init impedance measurement source
-        init_data = {'channel':   self.chan_key_list,
+        init_data = {'channel': self.chan_key_list,
                      'impedance': ['NA' for i in range(self.n_chan)],
-                     'row':       ['1' for i in range(self.n_chan)],
-                     'color':     ['black' for i in range(self.n_chan)]}
+                     'row': ['1' for i in range(self.n_chan)],
+                     'color': ['black' for i in range(self.n_chan)]}
         self.imp_source = ColumnDataSource(data=init_data)
 
         # Init timer source
@@ -161,12 +187,12 @@ def exg_callback(self, packet):
             # Baseline correction
             if self.baseline_widget.active:
                 samples_avg = exg.mean(axis=1)
-                if self._baseline_corrector["baseline"] is None:
+                baseline = self._baseline_corrector["baseline"]
+                ma_len = self._baseline_corrector["MA_length"]
+                if baseline is None:
                     self._baseline_corrector["baseline"] = samples_avg
                 else:
-                    self._baseline_corrector["baseline"] -= (
-                            (self._baseline_corrector["baseline"] - samples_avg) / self._baseline_corrector["MA_length"] *
-                            exg.shape[1])
+                    self._baseline_corrector["baseline"] -= ((baseline - samples_avg) / ma_len * exg.shape[1])
                 exg -= self._baseline_corrector["baseline"][:, np.newaxis]
             else:
                 self._baseline_corrector["baseline"] = None
@@ -243,17 +269,20 @@ def impedance_callback(self, packet):
              packet (explorepy.packet.EEG): ExG packet
         """
         if self.mode == "impedance":
-            imp = packet.get_impedances()
+            imp = packet.get_impedances() / 2
             color = []
             imp_status = []
             for value in imp:
-                if value > 500:
+                if value > 250:
                     color.append("black")
                     imp_status.append("Open")
-                elif value > 100:
+                elif value > 50:
+                    color.append("black")
+                    imp_status.append(str(round(value, 0)) + " K\u03A9")
+                elif value > 30:
                     color.append("red")
                     imp_status.append(str(round(value, 0)) + " K\u03A9")
-                elif value > 50:
+                elif value > 20:
                     color.append("orange")
                     imp_status.append(str(round(value, 0)) + " K\u03A9")
                 elif value > 10:
@@ -267,9 +296,9 @@ def impedance_callback(self, packet):
                     imp_status.append("<5K\u03A9")  # As the ADS is not precise in low values.
 
             data = {"impedance": imp_status,
-                    'channel':   self.chan_key_list,
-                    'row':       ['1' for i in range(self.n_chan)],
-                    'color':     color
+                    'channel': self.chan_key_list,
+                    'row': ['1' for i in range(self.n_chan)],
+                    'color': color
                     }
             self.doc.add_next_tick_callback(partial(self._update_imp, new_data=data))
         else:
@@ -530,8 +559,8 @@ def _init_imp_plot(self):
         plot.circle(x='channel', y="row", size=50, source=self.imp_source, fill_alpha=0.6, color="color",
                     line_color='color', line_width=2)
 
-        text_props = {"source":          self.imp_source, "text_align": "center",
-                      "text_color":      "white", "text_baseline": "middle", "text_font": "helvetica",
+        text_props = {"source": self.imp_source, "text_align": "center",
+                      "text_color": "white", "text_baseline": "middle", "text_font": "helvetica",
                       "text_font_style": "bold"}
 
         x = dodge("channel", -0.1, range=plot.x_range)
@@ -670,7 +699,7 @@ def _toggle_push2lsl(self, active):
 
     def _init_set_marker(self):
         self.marker_button = Button(label=u"Set", button_type="default", width=80, height=31, disabled=True)
-        self.event_code_input = TextInput(value="8", title="Event code:", width=80, disabled=True)
+        self.event_code_input = TextInput(value="0", title="Event code:", width=80, disabled=True)
         self.event_code_input.on_change('value', self._check_marker_value)
         self.marker_button.on_click(self._set_marker)
         return column([Spacer(width=170, height=5),
@@ -686,10 +715,10 @@ def _set_marker(self):
     def _check_marker_value(self, attr, old, new):
         try:
             code = int(self.event_code_input.value)
-            if code < 7 or code > 65535:
-                raise ValueError('Value must be an integer between 8 and 65535')
+            if code < 0 or code > 65535:
+                raise ValueError('Value must be an integer between 0 and 65535')
         except ValueError:
-            self.event_code_input.value = "7<val<65535"
+            self.event_code_input.value = "0<=val<=65535"
 
     @gen.coroutine
     @without_property_validation
@@ -724,8 +753,8 @@ def get_fft(exg, s_rate):
     explore = Explore()
     explore.stream_processor = StreamProcessor()
     explore.stream_processor.device_info = {'firmware_version': '0.0.0',
-                                            'adc_mask':         [1 for i in range(8)],
-                                            'sampling_rate':    250}
+                                            'adc_mask': [1 for i in range(8)],
+                                            'sampling_rate': 250}
 
     dashboard = Dashboard(explore=explore)
     dashboard.start_server()
diff --git a/src/explorepy/explore.py b/src/explorepy/explore.py
index 7a65e5fc..29c118bf 100644
--- a/src/explorepy/explore.py
+++ b/src/explorepy/explore.py
@@ -13,18 +13,39 @@
     >>> explore.visualize(bp_freq=(1, 40), notch_freq=50)
 """
 
+import logging
 import os
+import re
 import time
-from appdirs import user_cache_dir
+from datetime import datetime
 from threading import Timer
-import logging
+
 import numpy as np
-import re
+from appdirs import user_cache_dir
 
 import explorepy
-from explorepy.tools import create_exg_recorder, create_orn_recorder, create_marker_recorder, LslServer, PhysicalOrientation
-from explorepy.command import MemoryFormat, SetSPS, SoftReset, SetCh, ModuleDisable, ModuleEnable
-from explorepy.stream_processor import StreamProcessor, TOPICS
+from explorepy.command import (
+    MemoryFormat,
+    ModuleDisable,
+    ModuleEnable,
+    SetCh,
+    SetChTest,
+    SetSPS,
+    SoftReset
+)
+from explorepy.stream_processor import (
+    TOPICS,
+    StreamProcessor
+)
+from explorepy.tools import (
+    LslServer,
+    PhysicalOrientation,
+    create_exg_recorder,
+    create_marker_recorder,
+    create_meta_recorder,
+    create_orn_recorder
+)
+
 
 logger = logging.getLogger(__name__)
 
@@ -39,6 +60,14 @@ def __init__(self):
         self.lsl = {}
         self.device_name = None
 
+    @property
+    def is_measuring_imp(self):
+        """Return impedance status"""
+        imp_mode = False
+        if self.stream_processor:
+            imp_mode = self.stream_processor._is_imp_mode
+        return imp_mode
+
     def connect(self, device_name=None, mac_address=None):
         r"""
         Connects to the nearby device. If there are more than one device, the user is asked to choose one of them.
@@ -71,6 +100,18 @@ def disconnect(self):
         r"""Disconnects from the device
         """
         self.is_connected = False
+        self.device_name = None
+
+        if self.lsl:
+            self.stop_lsl()
+
+        if self.recorders:
+            self.stop_recording()
+
+        if self.is_measuring_imp:
+            self.stream_processor.disable_imp()
+            self.is_measuring_imp = False
+
         self.stream_processor.stop()
         logger.debug("Device has been disconnected.")
 
@@ -113,6 +154,7 @@ def record_data(self, file_name, do_overwrite=False, duration=None, file_type='c
         exg_out_file = file_name + "_ExG"
         orn_out_file = file_name + "_ORN"
         marker_out_file = file_name + "_Marker"
+        meta_out_file = file_name + "_Meta"
 
         self.recorders['exg'] = create_exg_recorder(filename=exg_out_file,
                                                     file_type=file_type,
@@ -125,13 +167,25 @@ def record_data(self, file_name, do_overwrite=False, duration=None, file_type='c
 
         if file_type == 'csv':
             self.recorders['marker'] = create_marker_recorder(filename=marker_out_file, do_overwrite=do_overwrite)
+            self.recorders['meta'] = create_meta_recorder(filename=meta_out_file,
+                                                          fs=self.stream_processor.device_info['sampling_rate'],
+                                                          adc_mask=self.stream_processor.device_info['adc_mask'],
+                                                          device_name=self.device_name,
+                                                          do_overwrite=do_overwrite,
+                                                          timestamp=datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
+            self.recorders['meta'].write_meta()
+            self.recorders['meta'].stop()
+
         elif file_type == 'edf':
             self.recorders['marker'] = self.recorders['exg']
+            logger.warning("Markers' timing might not be precise in EDF files. We recommend recording in CSV format "
+                           "if you are setting markers during the recording.")
 
         self.stream_processor.subscribe(callback=self.recorders['exg'].write_data, topic=TOPICS.raw_ExG)
         self.stream_processor.subscribe(callback=self.recorders['orn'].write_data, topic=TOPICS.raw_orn)
         self.stream_processor.subscribe(callback=self.recorders['marker'].set_marker, topic=TOPICS.marker)
         logger.info("Recording...")
+
         self.recorders['timer'] = Timer(duration, self.stop_recording)
 
         self.recorders['timer'].start()
@@ -157,6 +211,7 @@ def stop_recording(self):
                 self.recorders['marker'].stop()
             if self.recorders['timer'].is_alive():
                 self.recorders['timer'].cancel()
+
             self.recorders = {}
             logger.info('Recording stopped.')
         else:
@@ -180,9 +235,11 @@ def convert_bin(self, bin_file, out_dir='', file_type='edf', do_overwrite=False)
         assert os.path.isfile(bin_file), "Error: File does not exist!"
         assert extension == '.BIN', "File type error! File extension must be BIN."
         out_full_path = os.path.join(os.getcwd(), out_dir)
-        exg_out_file = out_full_path + filename + '_exg'
-        orn_out_file = out_full_path + filename + '_orn'
-        marker_out_file = out_full_path + filename + '_marker'
+        exg_out_file = out_full_path + filename + '_ExG'
+        orn_out_file = out_full_path + filename + '_ORN'
+        marker_out_file = out_full_path + filename + '_Marker'
+        meta_out_file = out_full_path + filename + '_Meta'
+
         self.stream_processor = StreamProcessor()
         self.stream_processor.read_device_info(bin_file=bin_file)
         self.recorders['exg'] = create_exg_recorder(filename=exg_out_file,
@@ -196,6 +253,13 @@ def convert_bin(self, bin_file, out_dir='', file_type='edf', do_overwrite=False)
 
         if self.recorders['file_type'] == 'csv':
             self.recorders['marker'] = create_marker_recorder(filename=marker_out_file, do_overwrite=do_overwrite)
+            self.recorders['meta'] = create_meta_recorder(filename=meta_out_file,
+                                                          fs=self.stream_processor.device_info['sampling_rate'],
+                                                          adc_mask=self.stream_processor.device_info['adc_mask'],
+                                                          device_name=self.device_name,
+                                                          do_overwrite=do_overwrite)
+            self.recorders['meta'].write_meta()
+            self.recorders['meta'].stop()
         else:
             self.recorders['marker'] = self.recorders['exg']
 
@@ -207,6 +271,7 @@ def device_info_callback(packet):
             new_device_info = packet.get_info()
             if not self.stream_processor.compare_device_info(new_device_info):
                 new_file_name = exg_out_file + "_" + str(np.round(packet.timestamp, 0))
+                new_meta_name = meta_out_file + "_" + str(np.round(packet.timestamp, 0))
                 logger.warning("Creating a new file: " + new_file_name + '.' + self.recorders['file_type'])
                 self.stream_processor.unsubscribe(callback=self.recorders['exg'].write_data, topic=TOPICS.raw_ExG)
                 self.stream_processor.unsubscribe(callback=self.recorders['marker'].set_marker, topic=TOPICS.marker)
@@ -216,15 +281,33 @@ def device_info_callback(packet):
                                                             fs=self.stream_processor.device_info['sampling_rate'],
                                                             adc_mask=self.stream_processor.device_info['adc_mask'],
                                                             do_overwrite=do_overwrite)
-                self.recorders['marker'] = self.recorders['exg']
+
+                if self.recorders['file_type'] == 'edf':
+                    self.recorders['marker'] = self.recorders['exg']
+
                 self.stream_processor.subscribe(callback=self.recorders['exg'].write_data, topic=TOPICS.raw_ExG)
                 self.stream_processor.subscribe(callback=self.recorders['marker'].set_marker, topic=TOPICS.marker)
 
+                if self.recorders['file_type'] == 'csv':
+                    self.recorders['meta'] = create_meta_recorder(
+                        filename=new_meta_name,
+                        fs=self.stream_processor.device_info['sampling_rate'],
+                        adc_mask=self.stream_processor.device_info['adc_mask'],
+                        device_name=self.device_name,
+                        do_overwrite=do_overwrite)
+                    self.recorders['meta'].write_meta()
+                    self.recorders['meta'].stop()
+
         self.stream_processor.subscribe(callback=device_info_callback, topic=TOPICS.device_info)
         self.stream_processor.open_file(bin_file=bin_file)
         logger.info("Converting...")
         while self.stream_processor.is_connected:
             time.sleep(.1)
+
+        if self.recorders['file_type'] == 'csv':
+            self.recorders["marker"].stop()
+        self.recorders["exg"].stop()
+        self.recorders["orn"].stop()
         logger.info('Conversion finished.')
 
     def push2lsl(self, duration=None, block=False):
@@ -294,10 +377,7 @@ def visualize(self, bp_freq=(1, 30), notch_freq=50):
 
     def measure_imp(self):
         """
-        Visualization of the electrode impedances
-
-        Args:
-            notch_freq (int): Notch frequency for filtering the line noise (50 or 60 Hz)
+        Visualization of the electrode impedance
         """
         self._check_connection()
         assert self.stream_processor.device_info['sampling_rate'] == 250, \
@@ -316,43 +396,59 @@ def set_marker(self, code):
         """Sets a digital event marker while streaming
 
         Args:
-            code (int): Marker code. It must be an integer larger than 7
-                        (codes from 0 to 7 are reserved for hardware markers).
+            code (int): Marker code (must be in range of 0-65535)
 
         """
         self._check_connection()
         self.stream_processor.set_marker(code=code)
 
     def format_memory(self):
-        """Format memory of the device"""
+        """Format memory of the device
+
+        Returns:
+            bool: True for success, False otherwise.
+        """
         self._check_connection()
         cmd = MemoryFormat()
-        self.stream_processor.configure_device(cmd)
+        return self.stream_processor.configure_device(cmd)
 
     def set_sampling_rate(self, sampling_rate):
         """Set sampling rate
 
         Args:
             sampling_rate (int): Desired sampling rate. Options: 250, 500, 1000
+
+        Returns:
+            bool: True for success, False otherwise
         """
         self._check_connection()
         if sampling_rate not in [250, 500, 1000]:
             raise ValueError("Sampling rate must be 250, 500 or 1000.")
         cmd = SetSPS(sampling_rate)
-        self.stream_processor.configure_device(cmd)
+        return self.stream_processor.configure_device(cmd)
 
     def reset_soft(self):
-        """Reset the device to the default settings"""
+        """Reset the device to the default settings
+
+        Note:
+            The Bluetooth will be disconnected by the Explore device after resetting.
+
+        Returns:
+            bool: True for success, False otherwise
+        """
         self._check_connection()
         cmd = SoftReset()
-        self.stream_processor.configure_device(cmd)
+        if self.stream_processor.configure_device(cmd):
+            self.disconnect()
+            return True
+        return False
 
     def set_channels(self, channel_mask):
         """Set the channel mask of the device
 
-        The channels can be disabled/enabled by calling this function and passing either bytes or binary string representing the mask.
-        For example in a 4 channel device, if you want to disable channel 4, the adc mask should be b'0111' (LSB is channel 1).
-        The inputs to this function can be b'0111' '0111'.
+        The channels can be disabled/enabled by calling this function and passing either bytes or binary string
+         representing the mask. For example in a 4 channel device, if you want to disable channel 4, the adc mask
+         should be b'0111' (LSB is channel 1). The inputs to this function can be b'0111' '0111'.
 
         Args:
             channel_mask (bytes str): Bytes or String representing the binary channel mask
@@ -362,21 +458,15 @@ def set_channels(self, channel_mask):
             >>> explore = Explore()
             >>> explore.connect(device_name='Explore_2FA2')
             >>> explore.set_channels(channel_mask='0111')  # disable channel 4 - mask:0111
-        """
-        c = re.compile('[^01]')
 
-        if (isinstance(channel_mask, str) and len(c.findall(channel_mask))==0) or (isinstance(channel_mask, bytes)):
-            channel_mask_int = int(channel_mask, 2)
-        # elif isinstance(channel_mask, int):
-        #     channel_mask_int = channel_mask
-        else:
-            # raise TypeError("Input must be an integer or a binary string!")
-            raise TypeError("Input must be bytes or binary string!")
+        Returns:
+            bool: True for success, False otherwise
+        """
+        channel_mask_int = self._convert_chan_mask(channel_mask)
 
         self._check_connection()
-        # cmd = SetCh(channel_mask)
         cmd = SetCh(channel_mask_int)
-        self.stream_processor.configure_device(cmd)
+        return self.stream_processor.configure_device(cmd)
 
     def disable_module(self, module_name):
         """Disable module
@@ -389,12 +479,15 @@ def disable_module(self, module_name):
             >>> explore = Explore()
             >>> explore.connect(device_name='Explore_2FA2')
             >>> explore.disable_module('ORN')
+
+        Returns:
+            bool: True for success, False otherwise
         """
         if module_name not in ['ORN', 'ENV', 'EXG']:
             raise ValueError('Module name must be one of ORN, ENV or EXG.')
         self._check_connection()
         cmd = ModuleDisable(module_name)
-        self.stream_processor.configure_device(cmd)
+        return self.stream_processor.configure_device(cmd)
 
     def enable_module(self, module_name):
         """Enable module
@@ -407,18 +500,21 @@ def enable_module(self, module_name):
             >>> explore = Explore()
             >>> explore.connect(device_name='Explore_2FA2')
             >>> explore.enable_module('ORN')
+
+        Returns:
+            bool: True for success, False otherwise
         """
         if module_name not in ['ORN', 'ENV', 'EXG']:
             raise ValueError('Module name must be one of ORN, ENV or EXG.')
         self._check_connection()
         cmd = ModuleEnable(module_name)
-        self.stream_processor.configure_device(cmd)
+        return self.stream_processor.configure_device(cmd)
 
     def calibrate_orn(self, do_overwrite=False):
         """Calibrate orientation module
 
-        This method calibrates orientation sensors in order to get the real physical orientation in addition to raw sensor
-        data. While running this function you would need to move and rotate the device. This function will store
+        This method calibrates orientation sensors in order to get the real physical orientation in addition to raw
+        sensor data. While running this function you would need to move and rotate the device. This function will store
         calibration info in the configuration file which will be used later during streaming to calculate physical
         orientation from raw sensor data.
 
@@ -426,15 +522,32 @@ def calibrate_orn(self, do_overwrite=False):
             do_overwrite: to overwrite the calibration data if already exists or not
 
         """
-        assert not (PhysicalOrientation.check_calibre_data(device_name=self.device_name) and not(do_overwrite)), \
+        assert not (PhysicalOrientation.check_calibre_data(device_name=self.device_name) and not do_overwrite), \
             "Calibration data already exists!"
         PhysicalOrientation.init_dir()
-        logger.info("Start recording for 100 seconds, please move the device around during this time, in all directions")
+        logger.info("Start recording for 100 seconds, "
+                    "please move the device around during this time, in all directions")
         file_name = user_cache_dir(appname="explorepy", appauthor="Mentalab") + '//temp_' + self.device_name
         self.record_data(file_name, do_overwrite=do_overwrite, duration=100, file_type='csv')
         time.sleep(105)
         PhysicalOrientation.calibrate(cache_dir=file_name, device_name=self.device_name)
 
+    def _activate_test_sig(self, channel_mask):
+        """ Activate the internal ADS test signals
+        """
+        channel_mask_int = self._convert_chan_mask(channel_mask)
+        self._check_connection()
+        cmd = SetChTest(channel_mask_int)
+        self.stream_processor.configure_device(cmd)
+
+    def _convert_chan_mask(self, mask):
+        c = re.compile('[^01]')
+
+        if (isinstance(mask, str) and len(c.findall(mask)) == 0) or (isinstance(mask, bytes)):
+            return int(mask, 2)
+        else:
+            raise TypeError("Input must be bytes or binary string!")
+
     def _check_connection(self):
         assert self.is_connected, "Explore device is not connected. Please connect the device first."
 
diff --git a/src/explorepy/exploresdk.py b/src/explorepy/exploresdk.py
index 96d5aaf8..f2556548 100644
--- a/src/explorepy/exploresdk.py
+++ b/src/explorepy/exploresdk.py
@@ -1,5 +1,5 @@
 # This file was automatically generated by SWIG (http://www.swig.org).
-# Version 4.0.2
+# Version 4.0.1
 #
 # Do not make changes to this file unless you know what you are doing--modify
 # the SWIG interface file instead.
@@ -262,6 +262,62 @@ def capacity(self) -> "std::vector< device >::size_type":
 # Register vectordevice in _exploresdk:
 _exploresdk.vectordevice_swigregister(vectordevice)
 
+class ExploreException(object):
+    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
+    __repr__ = _swig_repr
+
+    def __init__(self, message: "std::string"):
+        _exploresdk.ExploreException_swiginit(self, _exploresdk.new_ExploreException(message))
+
+    def what(self) -> "char const *":
+        return _exploresdk.ExploreException_what(self)
+    __swig_destroy__ = _exploresdk.delete_ExploreException
+
+# Register ExploreException in _exploresdk:
+_exploresdk.ExploreException_swigregister(ExploreException)
+
+class ExploreReadBufferException(object):
+    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
+    __repr__ = _swig_repr
+
+    def __init__(self, message: "std::string"):
+        _exploresdk.ExploreReadBufferException_swiginit(self, _exploresdk.new_ExploreReadBufferException(message))
+
+    def what(self) -> "char const *":
+        return _exploresdk.ExploreReadBufferException_what(self)
+    __swig_destroy__ = _exploresdk.delete_ExploreReadBufferException
+
+# Register ExploreReadBufferException in _exploresdk:
+_exploresdk.ExploreReadBufferException_swigregister(ExploreReadBufferException)
+
+class ExploreIOException(object):
+    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
+    __repr__ = _swig_repr
+
+    def __init__(self, message: "std::string"):
+        _exploresdk.ExploreIOException_swiginit(self, _exploresdk.new_ExploreIOException(message))
+
+    def what(self) -> "char const *":
+        return _exploresdk.ExploreIOException_what(self)
+    __swig_destroy__ = _exploresdk.delete_ExploreIOException
+
+# Register ExploreIOException in _exploresdk:
+_exploresdk.ExploreIOException_swigregister(ExploreIOException)
+
+class ExploreBtSocketException(object):
+    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
+    __repr__ = _swig_repr
+
+    def __init__(self, message: "std::string"):
+        _exploresdk.ExploreBtSocketException_swiginit(self, _exploresdk.new_ExploreBtSocketException(message))
+
+    def what(self) -> "char const *":
+        return _exploresdk.ExploreBtSocketException_what(self)
+    __swig_destroy__ = _exploresdk.delete_ExploreBtSocketException
+
+# Register ExploreBtSocketException in _exploresdk:
+_exploresdk.ExploreBtSocketException_swigregister(ExploreBtSocketException)
+
 class device(object):
     thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
     __repr__ = _swig_repr
diff --git a/src/explorepy/filters.py b/src/explorepy/filters.py
index 3a72a6d3..dd266329 100644
--- a/src/explorepy/filters.py
+++ b/src/explorepy/filters.py
@@ -1,12 +1,18 @@
 # -*- coding: utf-8 -*-
 """Filter module"""
 import copy
-import numpy as np
-from scipy.signal import butter, lfilter, iirfilter
 import logging
 
+import numpy as np
+from scipy.signal import (
+    butter,
+    iirfilter,
+    lfilter
+)
+
 from explorepy.packet import Packet
 
+
 logger = logging.getLogger(__name__)
 
 
@@ -25,17 +31,17 @@ def __init__(self, cutoff_freq, filter_type, s_rate, n_chan, order=5):
         nyq_freq = self.s_rate / 2.
         self.filter_type = filter_type
         self.filter_param = None
-        if filter_type is 'lowpass':
+        if filter_type == 'lowpass':
             hc_freq = cutoff_freq / nyq_freq
             if hc_freq >= 1.0:
                 logger.error("High cutoff frequency cannot be larger than or equal to the nyquist frequency. Setting"
-                             " the high cutoff frequency to %.1f Hz!", nyq_freq-1)
-                hc_freq = (nyq_freq-1)/nyq_freq
+                             " the high cutoff frequency to %.1f Hz!", nyq_freq - 1)
+                hc_freq = (nyq_freq - 1) / nyq_freq
 
             b, a = butter(order, hc_freq, btype='lowpass')
             zi = np.zeros((n_chan, order))
 
-        elif filter_type is 'highpass':
+        elif filter_type == 'highpass':
             lc_freq = cutoff_freq / nyq_freq
             if lc_freq <= 0.003:
                 logger.warning('Transient band for low cutoff frequency is too narrow. Low cutoff frequency is set to'
@@ -44,7 +50,7 @@ def __init__(self, cutoff_freq, filter_type, s_rate, n_chan, order=5):
             b, a = butter(order, lc_freq, btype='highpass')
             zi = np.zeros((n_chan, order))
 
-        elif filter_type is 'bandpass':
+        elif filter_type == 'bandpass':
             if cutoff_freq[0] >= cutoff_freq[1]:
                 logger.error("High cutoff frequency must be larger than low cutoff frequency. Applying a bandpass "
                              "filter with [1, 40]Hz frequency band instead. ")
@@ -54,18 +60,18 @@ def __init__(self, cutoff_freq, filter_type, s_rate, n_chan, order=5):
 
             if lc_freq <= 0.003:
                 logger.warning('Transient band for low cutoff frequency is too narrow. Low cutoff frequency is set to'
-                               ' %.2f Hz', 0.003*nyq_freq)
+                               ' %.2f Hz', 0.003 * nyq_freq)
                 lc_freq = 0.003
 
             if hc_freq >= 1.0:
                 logger.error("High cutoff frequency cannot be larger than or equal to the nyquist frequency. Setting"
-                             " the high cutoff frequency to %.1f Hz!", nyq_freq-1)
-                hc_freq = (nyq_freq-1)/nyq_freq
+                             " the high cutoff frequency to %.1f Hz!", nyq_freq - 1)
+                hc_freq = (nyq_freq - 1) / nyq_freq
 
             b, a = butter(order, [lc_freq, hc_freq], btype='band')
             zi = np.zeros((n_chan, order * 2))
 
-        elif filter_type is 'notch':
+        elif filter_type == 'notch':
             lc_freq = (cutoff_freq - 2) / nyq_freq
             hc_freq = (cutoff_freq + 2) / nyq_freq
             b, a = iirfilter(5, [lc_freq, hc_freq], btype='bandstop', ftype='butter')
diff --git a/src/explorepy/log_config.py b/src/explorepy/log_config.py
index 7daf32f6..8b49b0fc 100644
--- a/src/explorepy/log_config.py
+++ b/src/explorepy/log_config.py
@@ -1,24 +1,34 @@
 # -*- coding: utf-8 -*-
 """Logging configurator module"""
-import sys
-import os
-import threading
+import configparser
 import logging
 import logging.handlers
+import os
+import sys
+import threading
 import time
+
 import sentry_sdk
-from appdirs import user_log_dir
+from appdirs import (
+    user_config_dir,
+    user_log_dir
+)
+
 from explorepy._exceptions import DeviceNotFoundError
 
+
 _IGNORED_EXC_BY_SENTRY = [DeviceNotFoundError, FileExistsError]
-_IGNORED_LOGGERS = ['explorepy.parser', 'explorepy.btcpp']
 
+USER_SETTING_KEY = "user settings"
+SHARE_LOG_PERMISSION_KEY = "share_logs"
+APP_AUTHOUR = "Mentalab"
+APP_NAME = "explorepy"
 
 explorepy_logger = logging.getLogger('explorepy')
 explorepy_logger.propagate = False
 logger = logging.getLogger(__name__)
 
-log_path = user_log_dir(appname="explorepy", appauthor="Mentalab")
+log_path = user_log_dir(appname=APP_NAME, appauthor=APP_AUTHOUR)
 log_filename = 'explorepy.log'
 os.makedirs(log_path, exist_ok=True)
 file_formatter = logging.Formatter('%(asctime)s - %(name)s - [%(levelname)s] - [%(threadName)-10s] - %(message)s')
@@ -68,23 +78,93 @@ def run_with_except_hook(*args2, **kwargs2):
     threading.Thread.__init__ = init
 
 
+def read_config(section, var):
+    """Read config file and return the value of the requested variable
+
+    Args:
+        section (str): section name
+        var (str): variable name
+
+    Returns:
+        str: content of the requested variable, empty string if the file/section/variable is not found
+    """
+    config_file = os.path.join(user_config_dir(appname="explorepy", appauthor="Mentalab"), "conf.ini")
+    if os.path.isfile(config_file):
+        config = configparser.ConfigParser()
+        config.read(config_file)
+        if section in config and var in config[section]:
+            return config[section][var]
+    return ""
+
+
+def write_config(section, var, val):
+    """ Write to config file
+    Args:
+        section (str): section name
+        var (str): variable name
+        val (str): value
+    Exceptions:
+        ValueError: Raised if the inputs types are other than string.
+        OSError: Raised if there is an error during reading/writing config file.
+    Returns:
+        bool: True if the action is successful, otherwise False
+    """
+    if not (type(val) == str and type(section) == str and type(var) == str):
+        logger.error("Wrong input type. Inputs must be strings.")
+        raise ValueError("Wrong input type. Inputs must be strings.")
+
+    config_file = os.path.join(user_config_dir(appname="explorepy", appauthor="Mentalab"), "conf.ini")
+
+    config = configparser.ConfigParser()
+    if os.path.isfile(config_file):
+        config.read(config_file)
+        if not config.has_section(section):
+            config.add_section(section)
+    if not os.path.isfile(config_file):  # Create the dir and file
+        os.makedirs(user_config_dir(appname="explorepy", appauthor="Mentalab"), exist_ok=True)
+        config['DEFAULT'] = {'description': 'configurations for Explorepy'}
+        config.add_section(section)
+
+    config[section][var] = val
+
+    try:
+        with open(config_file, "w") as fid:
+            config.write(fid)
+    except OSError as error:
+        error_msg = f"Could not open file: {config_file}"
+        logger.error(error_msg)
+        raise error(error_msg)
+
+
 def uncaught_exception_handler(exctype, value, trace_back):
     """Handler of unhandled exceptions"""
     if exctype not in _IGNORED_EXC_BY_SENTRY:
-        time.sleep(3)
-        while True:
-            try:
-                txt = input("An unexpected error occurred! Do you want to send the error log to Mentalab? (y/n) \n>")
-            except (KeyboardInterrupt, EOFError):
-                sentry_sdk.init()  # disable sentry
-                break
-
-            if txt in ['n', 'no', 'N', 'No']:
-                sentry_sdk.init()  # disable sentry
-                break
-            if txt in ['y', 'yes', 'Y', 'Yes']:
-                logger.info("Thanks for helping us to improve Explorepy. Sending the error log to Mentalab ...")
-                break
+        permission = None
+
+        share_log_flag = read_config(USER_SETTING_KEY, SHARE_LOG_PERMISSION_KEY)
+        if share_log_flag == "True":
+            permission = True
+        elif share_log_flag == "False":
+            permission = False
+
+        time.sleep(2)
+        if permission is None:  # Then ask for permission
+            while True:
+                try:
+                    txt = input("An unexpected error occurred! "
+                                "Do you want to send the error log to Mentalab? (y/n) \n>")
+                except (KeyboardInterrupt, EOFError):
+                    sentry_sdk.init()  # disable sentry
+                    break
+
+                if txt in ['n', 'no', 'N', 'No']:
+                    sentry_sdk.init()  # disable sentry
+                    break
+                if txt in ['y', 'yes', 'Y', 'Yes']:
+                    logger.info("Thanks for helping us to improve Explorepy. Sending the error log to Mentalab ...")
+                    break
+        elif not permission:
+            sentry_sdk.init()  # disable sentry
     else:
         sentry_sdk.init()  # disable sentry for ignored exceptions
 
@@ -109,7 +189,5 @@ def set_sentry_tag(tag_key, tag_value):
     traces_sample_rate=1.0
 )
 
-for logger_name in _IGNORED_LOGGERS:
-    sentry_sdk.integrations.logging.ignore_logger(logger_name)
 setup_thread_excepthook()
 sys.excepthook = uncaught_exception_handler
diff --git a/src/explorepy/packet.py b/src/explorepy/packet.py
index 655cf5ad..ffca108d 100644
--- a/src/explorepy/packet.py
+++ b/src/explorepy/packet.py
@@ -1,14 +1,19 @@
 # -*- coding: utf-8 -*-
 """This module contains all packet classes of Mentalab Explore device"""
 import abc
+import logging
+import struct
 from enum import IntEnum
+
 import numpy as np
-import logging
 
 from explorepy._exceptions import FletcherError
 
+
 logger = logging.getLogger(__name__)
 
+TIMESTAMP_SCALE = 10000
+
 
 class PACKET_ID(IntEnum):
     """Packet ID enum"""
@@ -25,8 +30,10 @@ class PACKET_ID(IntEnum):
     EEG98R = 210
     CMDRCV = 192
     CMDSTAT = 193
-    MARKER = 194
+    PUSHMARKER = 194
     CALIBINFO = 195
+    TRIGGER_OUT = 177  # Trigger-out of Explore device
+    TRIGGER_IN = 178   # Trigger-in to Explore device
 
 
 EXG_UNIT = 1e-6
@@ -36,13 +43,16 @@ class Packet:
     """An abstract base class for Explore packet"""
     __metadata__ = abc.ABCMeta
 
-    def __init__(self, timestamp, payload):
+    def __init__(self, timestamp, payload, time_offset=0):
         """Gets the timestamp and payload and initializes the packet object
 
         Args:
-            payload (bytearray): a byte array including binary data and fletcher
+            timestamp (double): Raw timestamp of the packet
+            payload (bytearray): A byte array including binary data and fletcher
+            time_offset (double): Time offset defined by parser. It will be the timestamp of the first packet when
+                                    streaming in realtime. It will be zero while converting a binary file.
         """
-        self.timestamp = timestamp
+        self.timestamp = timestamp / TIMESTAMP_SCALE + time_offset
 
     @abc.abstractmethod
     def _convert(self, bin_data):
@@ -76,6 +86,11 @@ class EEG(Packet):
     """EEG packet class"""
     __metadata__ = abc.ABCMeta
 
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
+        self.data = None
+        self.imp_data = None
+
     def calculate_impedance(self, imp_calib_info):
         """calculate impedance with the help of impedance calibration info
 
@@ -83,8 +98,12 @@ def calculate_impedance(self, imp_calib_info):
             imp_calib_info (dict): dictionary of impedance calibration info including slope, offset and noise level
 
         """
-        self.imp_data = np.round((self.get_ptp() - imp_calib_info['noise_level']) * imp_calib_info['slope']/1.e6 -
-                                 imp_calib_info['offset'], decimals=0)
+        scale = imp_calib_info['slope']
+        offset = imp_calib_info['offset']
+        self.imp_data = np.round(
+            (self.get_ptp() - imp_calib_info['noise_level']) * scale / 1.e6 - offset,
+            decimals=0
+        )
 
     def get_data(self, exg_fs=None):
         """get time vector and data
@@ -106,11 +125,20 @@ def get_ptp(self):
         """Get peak to peak value"""
         return np.ptp(self.data, axis=1)
 
+    def __str__(self):
+        pass
+
+    def _check_fletcher(self, fletcher):
+        pass
+
+    def _convert(self, bin_data):
+        pass
+
 
 class EEG94(EEG):
     """EEG packet for 4 channel device"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -134,8 +162,8 @@ def __str__(self):
 
 class EEG98(EEG):
     """EEG packet for 8 channel device"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -159,8 +187,8 @@ def __str__(self):
 
 class EEG99s(EEG):
     """EEG packet for 8 channel device"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -184,8 +212,8 @@ def __str__(self):
 
 class EEG99(EEG):
     """EEG packet for 8 channel device"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -208,10 +236,12 @@ def __str__(self):
 
 class Orientation(Packet):
     """Orientation data packet"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
+        self.theta = None
+        self.rot_axis = None
 
     def _convert(self, bin_data):
         data = np.copy(np.frombuffer(bin_data, dtype=np.dtype(np.int16).newbyteorder('<'))).astype(np.float)
@@ -234,12 +264,12 @@ def get_data(self, srate=None):
 
     def compute_angle(self, matrix=None):
         """Compute physical angle"""
-        trace = matrix[0][0]+matrix[1][1]+matrix[2][2]
-        theta = np.arccos((trace-1)/2)*57.2958
+        trace = matrix[0][0] + matrix[1][1] + matrix[2][2]
+        theta = np.arccos((trace - 1) / 2) * 57.2958
         nx = matrix[2][1] - matrix[1][2]
         ny = matrix[0][2] - matrix[2][0]
         nz = matrix[1][0] - matrix[0][1]
-        rot_axis = 1/np.sqrt((3-trace)*(1+trace))*np.array([nx, ny, nz])
+        rot_axis = 1 / np.sqrt((3 - trace) * (1 + trace)) * np.array([nx, ny, nz])
         self.theta = theta
         self.rot_axis = rot_axis
         return [theta, rot_axis]
@@ -247,8 +277,8 @@ def compute_angle(self, matrix=None):
 
 class Environment(Packet):
     """Environment data packet"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -300,8 +330,8 @@ def _volt_to_percent(voltage):
 
 class TimeStamp(Packet):
     """Time stamp data packet"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
         self.raw_data = None
@@ -318,33 +348,124 @@ def __str__(self):
 
 
 class EventMarker(Packet):
-    """Marker packet"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
-        self._convert(payload[:-4])
-        self._check_fletcher(payload[-4:])
+    """Abstract class for event markers"""
+    __metadata__ = abc.ABCMeta
+
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
+        self.code = None
+        self._label_prefix = None
 
+    @abc.abstractmethod
     def _convert(self, bin_data):
-        self.marker_code = np.frombuffer(bin_data, dtype=np.dtype(np.uint16).newbyteorder('<'))[0]
+        pass
 
     def _check_fletcher(self, fletcher):
         if not fletcher == b'\xaf\xbe\xad\xde':
             raise FletcherError('Fletcher value is incorrect!')
 
-    def __str__(self):
-        return "Event marker: " + str(self.marker_code)
-
     def get_data(self, srate=None):
         """Get marker data
         Args:
             srate: NOT USED. Only for compatibility purpose"""
-        return [self.timestamp], [self.marker_code]
+        return [self.timestamp], [self._label_prefix + str(self.code)]
+
+    def __str__(self):
+        return f"{self.__class__.__name__}, Timestamp: {self.timestamp}, Code: {self.code}"
+
+
+class PushButtonMarker(EventMarker):
+    """Push Button Marker packet"""
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
+        self._convert(payload[:-4])
+        self._check_fletcher(payload[-4:])
+        self._label_prefix = 'pb_'
+
+    def _convert(self, bin_data):
+        self.code = np.frombuffer(bin_data, dtype=np.dtype(np.uint16).newbyteorder('<'))[0]
+
+
+class SoftwareMarker(EventMarker):
+    """Software marker packet"""
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
+        self._convert(payload[:-4])
+        self._check_fletcher(payload[-4:])
+        self._label_prefix = 'sw_'
+
+    def _convert(self, bin_data):
+        self.code = np.frombuffer(bin_data, dtype=np.dtype(np.uint16).newbyteorder('<'))[0]
+
+    @staticmethod
+    def create(local_time, code):
+        """ Create a software marker
+
+        Args:
+            local_time (double): Local time from LSL
+            code (int): Event marker code
+
+        Returns:
+            SoftwareMarker
+        """
+        return SoftwareMarker(local_time * TIMESTAMP_SCALE,
+                              payload=bytearray(struct.pack('<H', code) + b'\xaf\xbe\xad\xde')
+                              )
+
+
+class TriggerIn(EventMarker):
+    """Trigger in packet"""
+    def __init__(self, timestamp, payload, time_offset=0):
+        super(TriggerIn, self).__init__(timestamp, payload, time_offset)
+        self._time_offset = time_offset
+        self._convert(payload[:-4])
+        self._check_fletcher(payload[-4:])
+        self._label_prefix = 'in_'
+
+    def _convert(self, bin_data):
+        precise_ts = np.asscalar(np.frombuffer(bin_data,
+                                               dtype=np.dtype(np.uint32).newbyteorder('<'),
+                                               count=1,
+                                               offset=0))
+        self.timestamp = precise_ts / TIMESTAMP_SCALE + self._time_offset
+        code = np.asscalar(np.frombuffer(bin_data, dtype=np.dtype(np.uint16).newbyteorder('<'), count=1, offset=4))
+        self.code = code
+        mac_address = hex(int(np.frombuffer(bin_data, dtype=np.dtype(np.uint16).newbyteorder('<'), count=1, offset=6)))
+        self.mac_address = mac_address
+
+
+class TriggerOut(EventMarker):
+    """Trigger-out packet"""
+    def __init__(self, timestamp, payload, time_offset=0):
+        super(TriggerOut, self).__init__(timestamp, payload, time_offset)
+        self._time_offset = time_offset
+        self._convert(payload[:-4])
+        self._check_fletcher(payload[-4:])
+        self._label_prefix = 'out_'
+
+    def _convert(self, bin_data):
+        precise_ts = np.asscalar(np.frombuffer(bin_data,
+                                               dtype=np.dtype(np.uint32).newbyteorder('<'),
+                                               count=1,
+                                               offset=0))
+
+        self.timestamp = precise_ts / TIMESTAMP_SCALE + self._time_offset
+        code = np.asscalar(np.frombuffer(bin_data, dtype=np.dtype(np.uint16).newbyteorder('<'), count=1, offset=4))
+        """
+        if label == 240:
+            label = "Sync"
+        if label == 15:
+            label = "ADS_Start"
+        """
+        self.code = code
+        mac_address = hex(int(np.frombuffer(bin_data, dtype=np.dtype(np.uint16).newbyteorder('<'), count=1, offset=6)))
+        self.mac_address = mac_address
 
 
 class Disconnect(Packet):
     """Disconnect packet"""
-    def __init__(self, timestamp, payload):
-        super().__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super().__init__(timestamp, payload, time_offset)
         self._check_fletcher(payload)
 
     def _convert(self, bin_data):
@@ -360,8 +481,8 @@ def __str__(self):
 
 class DeviceInfo(Packet):
     """Device information packet"""
-    def __init__(self, timestamp, payload):
-        super(DeviceInfo, self).__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super(DeviceInfo, self).__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -392,8 +513,8 @@ def get_data(self):
 
 class CommandRCV(Packet):
     """Command Status packet"""
-    def __init__(self, timestamp, payload):
-        super(CommandRCV, self).__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super(CommandRCV, self).__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -410,8 +531,8 @@ def __str__(self):
 
 class CommandStatus(Packet):
     """Command Status packet"""
-    def __init__(self, timestamp, payload):
-        super(CommandStatus, self).__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super(CommandStatus, self).__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -429,8 +550,8 @@ def __str__(self):
 
 class CalibrationInfo(Packet):
     """Calibration Info packet"""
-    def __init__(self, timestamp, payload):
-        super(CalibrationInfo, self).__init__(timestamp, payload)
+    def __init__(self, timestamp, payload, time_offset=0):
+        super(CalibrationInfo, self).__init__(timestamp, payload, time_offset)
         self._convert(payload[:-4])
         self._check_fletcher(payload[-4:])
 
@@ -468,5 +589,7 @@ def __str__(self):
     PACKET_ID.CMDRCV: CommandRCV,
     PACKET_ID.CMDSTAT: CommandStatus,
     PACKET_ID.CALIBINFO: CalibrationInfo,
-    PACKET_ID.MARKER: EventMarker
+    PACKET_ID.PUSHMARKER: PushButtonMarker,
+    PACKET_ID.TRIGGER_IN: TriggerIn,
+    PACKET_ID.TRIGGER_OUT: TriggerOut
 }
diff --git a/src/explorepy/parser.py b/src/explorepy/parser.py
index e7b6ce92..8fa225b3 100755
--- a/src/explorepy/parser.py
+++ b/src/explorepy/parser.py
@@ -1,15 +1,20 @@
 # -*- coding: utf-8 -*-
 """Parser module"""
-from threading import Thread
-import struct
 import asyncio
 import logging
+import struct
+from threading import Thread
 
 import explorepy
-from explorepy.packet import PACKET_CLASS_DICT, DeviceInfo
-from explorepy._exceptions import *
+from explorepy._exceptions import FletcherError
+from explorepy.packet import (
+    PACKET_CLASS_DICT,
+    TIMESTAMP_SCALE,
+    DeviceInfo
+)
 from explorepy.tools import get_local_time
 
+
 logger = logging.getLogger(__name__)
 
 
@@ -26,7 +31,11 @@ def __init__(self, callback, mode='device'):
         self.device_configurator = None
         self.callback = callback
 
-        self._time_offset = None
+        if self.mode == 'file':
+            self._time_offset = 0
+        else:
+            self._time_offset = None
+
         self._do_streaming = False
         self.is_waiting = False
         self._stream_thread = None
@@ -130,33 +139,29 @@ def _generate_packet(self):
 
         # Timestamp conversion
         if self._time_offset is None:
-            self._time_offset = get_local_time() - timestamp/10000
+            self._time_offset = get_local_time() - timestamp / TIMESTAMP_SCALE
             timestamp = 0
-        else:
-            timestamp = timestamp/10000 + self._time_offset
 
         payload_data = self.stream_interface.read(payload - 4)
         packet = self._parse_packet(pid, timestamp, payload_data)
         return packet
 
-    @staticmethod
-    def _parse_packet(pid, timestamp, bin_data):
+    def _parse_packet(self, pid, timestamp, bin_data):
         """Generates the packets according to the pid
 
         Args:
             pid (int): Packet ID
             timestamp (int): Timestamp
-            bin_data: Binary dat
+            bin_data: Binary data
 
         Returns:
             Packet
         """
 
         if pid in PACKET_CLASS_DICT:
-                packet = PACKET_CLASS_DICT[pid](timestamp, bin_data)
+            packet = PACKET_CLASS_DICT[pid](timestamp, bin_data, self._time_offset)
         else:
             logger.debug("Unknown Packet ID:" + str(pid))
-            # raise ValueError("Unknown Packet ID:" + str(pid))
             packet = None
         return packet
 
diff --git a/src/explorepy/stream_processor.py b/src/explorepy/stream_processor.py
index da3e133a..b481d9cd 100644
--- a/src/explorepy/stream_processor.py
+++ b/src/explorepy/stream_processor.py
@@ -2,20 +2,39 @@
 """Stream Processor module
 This module is responsible for processing incoming stream from Explore device and publishing data to subscribers.
 """
-from enum import Enum
-import time
-import struct
 import logging
+import time
+from enum import Enum
+from threading import Lock
 
-from explorepy.parser import Parser
-from explorepy.packet import DeviceInfo, CommandRCV, CommandStatus, EEG, Orientation, \
-    Environment, EventMarker, CalibrationInfo
+from explorepy.command import (
+    DeviceConfiguration,
+    ZMeasurementDisable,
+    ZMeasurementEnable
+)
 from explorepy.filters import ExGFilter
-from explorepy.command import DeviceConfiguration, ZMeasurementEnable, ZMeasurementDisable
-from explorepy.tools import ImpedanceMeasurement, PhysicalOrientation, get_local_time
+from explorepy.packet import (
+    EEG,
+    CalibrationInfo,
+    CommandRCV,
+    CommandStatus,
+    DeviceInfo,
+    Environment,
+    EventMarker,
+    Orientation,
+    SoftwareMarker
+)
+from explorepy.parser import Parser
+from explorepy.tools import (
+    ImpedanceMeasurement,
+    PhysicalOrientation,
+    get_local_time
+)
+
 
 TOPICS = Enum('Topics', 'raw_ExG filtered_ExG device_info marker raw_orn mapped_orn cmd_ack env cmd_status imp')
 logger = logging.getLogger(__name__)
+lock = Lock()
 
 
 class StreamProcessor:
@@ -34,6 +53,8 @@ def __init__(self):
         self.is_connected = False
         self._is_imp_mode = False
         self.physical_orn = PhysicalOrientation()
+        self._last_packet_timestamp = 0
+        self._last_packet_rcv_time = 0
 
     def subscribe(self, callback, topic):
         """Subscribe a function to a topic
@@ -42,8 +63,9 @@ def subscribe(self, callback, topic):
             callback (function): Callback function to be called when there is a new packet in the topic
             topic (enum 'Topics'): Topic type
         """
-        logger.debug(f"Subscribe {callback.__name__} to {topic}")
-        self.subscribers.setdefault(topic, set()).add(callback)
+        with lock:
+            logger.debug(f"Subscribe {callback.__name__} to {topic}")
+            self.subscribers[topic].add(callback)
 
     def unsubscribe(self, callback, topic):
         """Unsubscribe a function from a topic
@@ -52,8 +74,9 @@ def unsubscribe(self, callback, topic):
             callback (function): Callback function to be called when there is a new packet in the topic
             topic (enum 'Topics'): Topic type
         """
-        logger.debug(f"Unsubscribe {callback} from {topic}")
-        self.subscribers.setdefault(topic, set()).discard(callback)
+        with lock:
+            logger.debug(f"Unsubscribe {callback} from {topic}")
+            self.subscribers[topic].discard(callback)
 
     def start(self, device_name=None, mac_address=None):
         """Start streaming from Explore device
@@ -77,7 +100,7 @@ def open_file(self, bin_file):
         """Open the binary file and read until it gets device info packet
         Args:
             bin_file (str): Path to binary file
-            """
+        """
         self.parser = Parser(callback=self.process, mode='file')
         self.is_connected = True
         self.parser.start_reading(filename=bin_file)
@@ -97,12 +120,14 @@ def process(self, packet):
         Args:
             packet (explorepy.packet.Packet): Data packet
         """
+        received_time = get_local_time()
         if isinstance(packet, Orientation):
             self.dispatch(topic=TOPICS.raw_orn, packet=packet)
             if self.physical_orn.status == "READY":
                 packet = self.physical_orn.calculate(packet=packet)
                 self.dispatch(topic=TOPICS.mapped_orn, packet=packet)
         elif isinstance(packet, EEG):
+            self._update_last_time_point(packet, received_time)
             self.dispatch(topic=TOPICS.raw_ExG, packet=packet)
             if self._is_imp_mode and self.imp_calculator:
                 packet_imp = self.imp_calculator.measure_imp(packet=packet)
@@ -126,6 +151,33 @@ def process(self, packet):
         elif not packet:
             self.is_connected = False
 
+    def _update_last_time_point(self, packet, received_time):
+        """Update the last PCB time point and the local time the last packet is received.
+
+        The goal is to keep track of the PCB clock (i.e. the PCB timestamp of the last packet that has been received)
+        and the local (client) time it has been received by the computer.
+
+        Args:
+            packet (explorepy.packet.EEG): ExG data packet
+            received_time (float): Local time of receiving the packet
+        """
+        if 'sampling_rate' in self.device_info:
+            timestamp, _ = packet.get_data(exg_fs=self.device_info['sampling_rate'])
+            timestamp = timestamp[-1]
+            with lock:
+                if timestamp > self._last_packet_timestamp:
+                    self._last_packet_timestamp = timestamp
+                    self._last_packet_rcv_time = received_time
+
+    def _get_sw_marker_time(self):
+        """Returns a timestamp to be used in software marker
+
+        This method gives an estimation of a timestamp relative to Explore internal clock. This timestamp can be used
+        for generating a software marker.
+        """
+        with lock:
+            return self._last_packet_timestamp + get_local_time() - self._last_packet_rcv_time
+
     def dispatch(self, topic, packet):
         """Dispatch a packet to subscribers
 
@@ -134,8 +186,9 @@ def dispatch(self, topic, packet):
             packet (explorepy.packet.Packet): Data packet
         """
         if self.subscribers:
-            for callback in self.subscribers[topic]:
-                callback(packet)
+            with lock:
+                for callback in self.subscribers[topic]:
+                    callback(packet)
 
     def add_filter(self, cutoff_freq, filter_type):
         """Add filter to the stream
@@ -151,13 +204,12 @@ def add_filter(self, cutoff_freq, filter_type):
                                       filter_type=filter_type,
                                       s_rate=self.device_info['sampling_rate'],
                                       n_chan=self.device_info['adc_mask'].count(1)))
-    
+
     def remove_filters(self):
-        '''
+        """
         Remove all filters from the stream
-        '''
-        logger.info(f"Removing all filters.")
-        # logger.info(f"Removing the {filter_type} filter.")
+        """
+        logger.info("Removing all filters.")
         while not self.device_info:
             logger.warning('No device info is available. Waiting for device info packet...')
             time.sleep(.2)
@@ -173,6 +225,9 @@ def configure_device(self, cmd):
 
         Args:
             cmd (explorepy.command.Command): Command to be sent
+
+        Returns:
+            bool: True for success, False otherwise.
         """
         if not self.is_connected:
             raise ConnectionError("No Explore device is connected!")
@@ -207,19 +262,19 @@ def orn_initialize(self, device_name):
             self.physical_orn.status = "READY"
         else:
             self.physical_orn.status = "NOT READY"
-            logger.info('Calibration coefficients for physical orientation do not exist. If you need physical orientation,'
-                        ' calibrate the device first.')
+            logger.debug('Calibration coefficients for physical orientation do not exist. '
+                         'If you need physical orientation, calibrate the device first.')
 
     def set_marker(self, code):
         """Set a marker in the stream"""
-        logger.info(f"Setting a marker with code: {code}")
+        logger.info(f"Setting a software marker with code: {code}")
         if not isinstance(code, int):
             raise TypeError('Marker code must be an integer!')
-        if 0 <= code <= 7:
-            raise ValueError('Marker code value is not valid')
+        if not 0 <= code <= 65535:
+            raise ValueError('Marker code value is not valid! Code must be in range of 0-65535.')
 
-        self.process(EventMarker(timestamp=get_local_time(),
-                                 payload=bytearray(struct.pack('<H', code) + b'\xaf\xbe\xad\xde')))
+        marker = SoftwareMarker.create(self._get_sw_marker_time(), code)
+        self.process(marker)
 
     def compare_device_info(self, new_device_info):
         """Compare a device info dict with the current version
diff --git a/src/explorepy/tools.py b/src/explorepy/tools.py
index 39f6defc..43a6a100 100644
--- a/src/explorepy/tools.py
+++ b/src/explorepy/tools.py
@@ -1,26 +1,40 @@
 # -*- coding: utf-8 -*-
 """Some useful tools such as file recorder, heart rate estimation, etc. used in explorepy"""
+import configparser
+import copy
+import csv
 import datetime
+import logging
 import os.path
-import csv
-import copy
 import socket
+from collections import namedtuple
 from contextlib import closing
+from threading import Lock
+
 import numpy as np
-from scipy import signal
 import pyedflib
-from pylsl import StreamInfo, StreamOutlet, local_clock
-import configparser
-from appdirs import user_cache_dir, user_config_dir
-import logging
+from appdirs import (
+    user_cache_dir,
+    user_config_dir
+)
+from pylsl import (
+    StreamInfo,
+    StreamOutlet,
+    local_clock
+)
+from scipy import signal
 
 import explorepy
 from explorepy.filters import ExGFilter
 
+
 logger = logging.getLogger(__name__)
+lock = Lock()
 
 EXG_CHANNELS = ['ch1', 'ch2', 'ch3', 'ch4', 'ch5', 'ch6', 'ch7', 'ch8']
 EXG_UNITS = ['uV' for ch in EXG_CHANNELS]
+EXG_MAX_LIM = 400000
+EXG_MIN_LIM = -400000
 ORN_CHANNELS = ['ax', 'ay', 'az', 'gx', 'gy', 'gz', 'mx', 'my', 'mz']
 ORN_UNITS = ['mg', 'mg', 'mg', 'mdps', 'mdps', 'mdps', 'mgauss', 'mgauss', 'mgauss']
 
@@ -35,53 +49,71 @@ def get_local_time():
 
 
 def bt_scan():
-    """"Scan for bluetooth devices
-    Scans for available explore devices.
-    Prints out MAC address and name of each found device
+    """ Scan for nearby Explore devices
 
-    Args:
+    This function searches for nearby bluetooth devices and returns a list of advertising Explore devices.
 
-    Returns:
+    Note:
+        In Windows, this function returns all the paired devices and unpaired advertising devices. The 'is_paired'
+        attribute shows if the device is paired. If a device is paired, it will be in the returned list regardless if
+        it is currently advertising or not.
 
+    Returns:
+            list[namedtuple]: list of nearby devices
     """
+    NearbyDeviceInfo = namedtuple("NearbyDeviceInfo", ["name", "address", "is_paired"])
     logger.info("Searching for nearby devices...")
     explore_devices = []
     print('\n')
-    if explorepy.get_bt_interface() == 'sdk':
-        device_manager = explorepy.exploresdk.ExploreSDK_Create()
-        nearby_devices = device_manager.PerformDeviceSearch()
-        for bt_device in nearby_devices:
-            if "Explore" in bt_device.name:
-                print("Device found: %s - %s" % (bt_device.name, bt_device.address))
-                explore_devices.append((bt_device.name, bt_device.address))
-    else:
-        import bluetooth
-        nearby_devices = bluetooth.discover_devices(lookup_names=True)
-        for address, name in nearby_devices:
-            if "Explore" in name:
-                print("Device found: %s - %s" % (name, address))
-                explore_devices.append((address, name))
+    device_manager = explorepy.exploresdk.ExploreSDK_Create()
+    nearby_devices = device_manager.PerformDeviceSearch()
+    for bt_device in nearby_devices:
+        if "Explore" in bt_device.name:
+            print("Device found: %s - %s - Paired: %s" % (bt_device.name, bt_device.address, bt_device.authenticated))
+            explore_devices.append(NearbyDeviceInfo(bt_device.name, bt_device.address, bt_device.authenticated))
 
     if not nearby_devices:
-        print("No Devices found")
+        logger.info("No Explore device was found!")
 
     return explore_devices
 
 
 def create_exg_recorder(filename, file_type, adc_mask, fs, do_overwrite):
+    """ Create ExG recorder
+
+    Args:
+        filename (str): file name
+        file_type (str): file type
+        adc_mask (str): channel mask
+        fs (int): sampling rate
+        do_overwrite (bool): overwrite if the file already exists
+
+    Returns:
+        FileRecorder: file recorder object
+    """
     exg_ch = ['TimeStamp'] + EXG_CHANNELS
-    exg_ch = [exg_ch[0]] + [exg_ch[i+1] for i, flag in enumerate(reversed(adc_mask)) if flag == 1]
+    exg_ch = [exg_ch[0]] + [exg_ch[i + 1] for i, flag in enumerate(reversed(adc_mask)) if flag == 1]
     exg_unit = ['s'] + EXG_UNITS
     exg_unit = [exg_unit[0]] + [exg_unit[i + 1] for i, flag in enumerate(reversed(adc_mask)) if flag == 1]
-    exg_max = [21600.] + [4e5 for i in range(8)]
+    exg_max = [21600.] + [EXG_MAX_LIM for i in range(8)]
     exg_max = [exg_max[0]] + [exg_max[i + 1] for i, flag in enumerate(reversed(adc_mask)) if flag == 1]
-    exg_min = [0.] + [-4e5 for i in range(8)]
+    exg_min = [0.] + [EXG_MIN_LIM for i in range(8)]
     exg_min = [exg_min[0]] + [exg_min[i + 1] for i, flag in enumerate(reversed(adc_mask)) if flag == 1]
     return FileRecorder(filename=filename, ch_label=exg_ch, fs=fs, ch_unit=exg_unit,
                         file_type=file_type, do_overwrite=do_overwrite, ch_min=exg_min, ch_max=exg_max)
 
 
 def create_orn_recorder(filename, file_type, do_overwrite):
+    """ Create orientation data recorder
+
+    Args:
+        filename (str): file name
+        file_type (str): file type
+        do_overwrite (bool): overwrite if the file already exists
+
+    Returns:
+        FileRecorder: file recorder object
+    """
     orn_ch = ['TimeStamp'] + ORN_CHANNELS
     orn_unit = ['s'] + ORN_UNITS
     orn_max = [21600., 2000, 2000, 2000, 250000, 250000, 250000, 50000, 50000, 50000]
@@ -91,12 +123,43 @@ def create_orn_recorder(filename, file_type, do_overwrite):
 
 
 def create_marker_recorder(filename, do_overwrite):
+    """ Create marker recorder
+
+    Args:
+        filename (str): file name
+        do_overwrite (str): overwrite if the file already exists
+
+    Returns:
+        FileRecorder: file recorder object
+    """
     marker_ch = ['TimeStamp', 'Code']
     marker_unit = ['s', '-']
     return FileRecorder(filename=filename, ch_label=marker_ch, fs=0, ch_unit=marker_unit,
                         file_type='csv', do_overwrite=do_overwrite)
 
 
+def create_meta_recorder(filename, fs, adc_mask, device_name, do_overwrite, timestamp=''):
+    """ Create meta file recorder
+
+    Args:
+        filename (str): file name
+        fs (int): sampling rate
+        adc_mask (str): channel mask
+        device_name (str): device name
+        do_overwrite (str): overwrite if the file already exists
+        timestamp (datetime): The time at which this recording starts. Defaults to None
+
+    Returns:
+        FileRecorder: file recorder object
+    """
+    header = ['DateTime', 'Device', 'sr', 'adcMask', 'ExGUnits']
+    exg_unit = 'mV'
+    if EXG_UNITS:
+        exg_unit = EXG_UNITS[0]  # we only need the first channel's units as this will correspond with the rest
+    return FileRecorder(filename=filename, file_type='csv', ch_label=header, fs=fs, ch_unit=exg_unit,
+                        adc_mask=adc_mask, device_name=device_name, do_overwrite=do_overwrite, timestamp=timestamp)
+
+
 class HeartRateEstimator:
     def __init__(self, fs=250, smoothing_win=20):
         """Real-time heart Rate Estimator class This class provides the tools for heart rate estimation. It basically detects
@@ -149,18 +212,18 @@ def heart_rate(self):
         if len(self.r_peaks_buffer) < 7:
             logger.warning('Few peaks to get heart rate! Noisy signal!')
             return 'NA'
-        else:
-            r_times = [item[1] for item in self.r_peaks_buffer]
-            rr_intervals = np.diff(r_times, 1)
-            if True in (rr_intervals > 3.):
-                logger.warning('Missing peaks! Noisy signal!')
-                return 'NA'
-            else:
-                estimated_heart_rate = int(1. / np.mean(rr_intervals) * 60)
-                if estimated_heart_rate > 140 or estimated_heart_rate < 40:
-                    logger.warning('Estimated heart rate <40 or >140! Potentially due to noisy signal!')
-                    estimated_heart_rate = 'NA'
-                return estimated_heart_rate
+
+        r_times = [item[1] for item in self.r_peaks_buffer]
+        rr_intervals = np.diff(r_times, 1)
+        if True in (rr_intervals > 3.):
+            logger.warning('Missing peaks! Noisy signal!')
+            return 'NA'
+
+        estimated_heart_rate = int(1. / np.mean(rr_intervals) * 60)
+        if estimated_heart_rate > 140 or estimated_heart_rate < 40:
+            logger.warning('Estimated heart rate <40 or >140! Potentially due to noisy signal!')
+            estimated_heart_rate = 'NA'
+        return estimated_heart_rate
 
     def _push_r_peak(self, val, time):
         self.r_peaks_buffer.append((val, time))
@@ -318,7 +381,7 @@ class FileRecorder:
 
     """
 
-    def __init__(self, filename, ch_label, fs, ch_unit, ch_min=None, ch_max=None,
+    def __init__(self, filename, ch_label, fs, ch_unit, timestamp=None, adc_mask=None, ch_min=None, ch_max=None,
                  device_name='Explore', file_type='edf', do_overwrite=False):
         """
 
@@ -327,6 +390,8 @@ def __init__(self, filename, ch_label, fs, ch_unit, ch_min=None, ch_max=None,
             ch_label (list): List of channel labels.
             fs (int): Sampling rate (must be identical for all channels)
             ch_unit (list): List of channels unit (e.g. 'uV', 'mG', 's', etc.)
+            timestamp (datetime): The time at which this recording starts
+            adc_mask (str): Channel mask
             ch_min (list): List of minimum value of each channel. Only needed in edf mode (can be None in csv mode)
             ch_max (list): List of maximum value of each channel. Only needed in edf mode (can be None in csv mode)
             device_name (str): Recording device name
@@ -340,8 +405,10 @@ def __init__(self, filename, ch_label, fs, ch_unit, ch_min=None, ch_max=None,
 
         self._file_obj = None
         self.file_type = file_type
+        self.timestamp = timestamp
         self._ch_label = ch_label
         self._ch_unit = ch_unit
+        self.adc_mask = adc_mask
         self._ch_max = ch_max
         self._ch_min = ch_min
         self._n_chan = len(ch_label)
@@ -356,6 +423,8 @@ def __init__(self, filename, ch_label, fs, ch_unit, ch_min=None, ch_max=None,
             self._create_edf(do_overwrite=do_overwrite)
             self._init_edf_channels()
             self._data = np.zeros((self._n_chan, 0))
+            self._annotations_buffer = []
+            self._timestamps = []
         elif file_type == 'csv':
             self._file_name = filename + '.csv'
             self._create_csv(do_overwrite=do_overwrite)
@@ -384,7 +453,9 @@ def stop(self):
         assert self._file_obj is not None, "Usage Error: File object has not been created yet."
         if self.file_type == 'edf':
             if self._data.shape[1] > 0:
-                self._file_obj.writeSamples(list(self._data))
+                with lock:
+                    self._file_obj.writeSamples(list(self._data))
+                    self._write_edf_anno()
             self._file_obj.close()
             self._file_obj = None
         elif self.file_type == 'csv':
@@ -396,15 +467,15 @@ def _init_edf_channels(self):
 
         ch_info_list = []
         for ch in zip(self._ch_label, self._ch_unit, self._ch_max, self._ch_min):
-            ch_info_list.append({'label':        ch[0],
-                                 'dimension':    ch[1],
-                                 'sample_rate':  self._fs,
+            ch_info_list.append({'label': ch[0],
+                                 'dimension': ch[1],
+                                 'sample_rate': self._fs,
                                  'physical_max': ch[2],
                                  'physical_min': ch[3],
-                                 'digital_max':  8388607,
-                                 'digital_min':  -8388608,
-                                 'prefilter':    '',
-                                 'transducer':   ''
+                                 'digital_max': 8388607,
+                                 'digital_min': -8388608,
+                                 'prefilter': '',
+                                 'transducer': ''
                                  })
         for i, ch_info in enumerate(ch_info_list):
             self._file_obj.setSignalHeader(i, ch_info)
@@ -420,28 +491,40 @@ def write_data(self, packet):
             packet (explorepy.packet.Packet): ExG or Orientation packet
 
         """
-        time_vector, signal = packet.get_data(self._fs)
+        time_vector, sig = packet.get_data(self._fs)
 
         if len(time_vector) == 1:
-            data = np.array(time_vector + signal)[:, np.newaxis]
+            data = np.array(time_vector + sig)[:, np.newaxis]
         else:
             if self._rec_time_offset is None:
                 self._rec_time_offset = time_vector[0]
-            data = np.concatenate((np.array(time_vector)[:, np.newaxis].T, np.array(signal)), axis=0)
+            data = np.concatenate((np.array(time_vector)[:, np.newaxis].T, np.array(sig)), axis=0)
         data = np.round(data, 4)
 
         if self.file_type == 'edf':
             if data.shape[0] != self._n_chan:
                 raise ValueError('Input first dimension must be {}'.format(self._n_chan))
             self._data = np.concatenate((self._data, data), axis=1)
-
-            if self._data.shape[1] > self._fs:
-                self._file_obj.writeSamples(list(self._data[:, :self._fs]))
-                self._data = self._data[:, self._fs:]
+            self._timestamps += list(data[0, :])
+            with lock:
+                if self._data.shape[1] > self._fs:
+                    self._file_obj.writeSamples(list(self._data[:, :self._fs]))
+                    self._write_edf_anno()
+                    self._data = self._data[:, self._fs:]
         elif self.file_type == 'csv':
             self._csv_obj.writerows(data.T.tolist())
             self._file_obj.flush()
 
+    def _write_edf_anno(self):
+        """write annotations in EDF file"""
+        for ts, code in list(self._annotations_buffer):
+            # correct clock deviations
+            idx = np.argmax(self._timestamps > ts) - 1
+            if idx != -1:
+                timestamp = idx / self.fs
+                self._file_obj.writeAnnotation(timestamp, 0.001, code)
+                self._annotations_buffer.remove((ts, code))  # remove the written annotation from original buffer
+
     def set_marker(self, packet):
         """Writes a marker event in the file
 
@@ -449,14 +532,23 @@ def set_marker(self, packet):
             packet (explorepy.packet.EventMarker): Event marker packet
 
         """
+        timestamp, code = packet.get_data()
+        timestamp[0] = round(timestamp[0], 4)
         if self.file_type == 'csv':
-            self.write_data(packet=packet)
+            data = timestamp + code
+            self._csv_obj.writerow(data)
+            self._file_obj.flush()
         elif self.file_type == 'edf':
-            timestamp, code = packet.get_data()
             if self._rec_time_offset is None:
                 self._rec_time_offset = timestamp[0]
-            timestamp = timestamp-np.float64(self._rec_time_offset)
-            self._file_obj.writeAnnotation(timestamp[0], 0.001, str(int(code[0])))
+            self._annotations_buffer.append((timestamp[0], code[0]))
+
+    def write_meta(self):
+        """Writes meta data in the file"""
+        channels = ['ch' + str(i + 1) for i, flag in enumerate(reversed(self.adc_mask)) if flag == 1]
+        row = [self.timestamp, self._device_name, self._fs, str(' '.join(channels)), self._ch_unit]
+        self._csv_obj.writerow(row)
+        self._file_obj.flush()
 
 
 class LslServer:
@@ -466,12 +558,12 @@ def __init__(self, device_info):
         self.exg_fs = device_info['sampling_rate']
         orn_fs = 20
 
-        info_exg = StreamInfo(name=device_info["device_name"]+"_ExG",
+        info_exg = StreamInfo(name=device_info["device_name"] + "_ExG",
                               type='ExG',
                               channel_count=n_chan,
                               nominal_srate=self.exg_fs,
                               channel_format='float32',
-                              source_id=device_info["device_name"]+"_ExG")
+                              source_id=device_info["device_name"] + "_ExG")
         info_exg.desc().append_child_value("manufacturer", "Mentalab")
         channels = info_exg.desc().append_child("channels")
         for i, mask in enumerate(device_info['adc_mask']):
@@ -481,12 +573,12 @@ def __init__(self, device_info):
                     .append_child_value("unit", EXG_UNITS[i])\
                     .append_child_value("type", "ExG")
 
-        info_orn = StreamInfo(name=device_info["device_name"]+"_ORN",
+        info_orn = StreamInfo(name=device_info["device_name"] + "_ORN",
                               type='ORN',
                               channel_count=9,
                               nominal_srate=orn_fs,
                               channel_format='float32',
-                              source_id=device_info["device_name"]+"_ORN")
+                              source_id=device_info["device_name"] + "_ORN")
         info_orn.desc().append_child_value("manufacturer", "Mentalab")
         channels = info_exg.desc().append_child("channels")
         for chan, unit in zip(ORN_CHANNELS, ORN_UNITS):
@@ -495,18 +587,19 @@ def __init__(self, device_info):
                 .append_child_value("unit", unit) \
                 .append_child_value("type", "ORN")
 
-        info_marker = StreamInfo(name=device_info["device_name"]+"_Marker",
+        info_marker = StreamInfo(name=device_info["device_name"] + "_Marker",
                                  type='Markers',
                                  channel_count=1,
                                  nominal_srate=0,
-                                 channel_format='int32',
-                                 source_id=device_info["device_name"]+"_Markers")
-
-        logger.info("LSL Streams have been created with names/source IDs as the following:\n" +
-                    "\t\t\t\t\t" + device_info["device_name"]+"_ExG\n" +
-                    "\t\t\t\t\t" + device_info["device_name"] + "_ORN\n" +
-                    "\t\t\t\t\t" + device_info["device_name"] + "_Markers\n"
-                    )
+                                 channel_format='string',
+                                 source_id=device_info["device_name"] + "_Markers")
+
+        logger.info(
+            f"LSL Streams have been created with names/source IDs as the following:\n"
+            f"\t\t\t\t\t {device_info['device_name']}_ExG\n"
+            f"\t\t\t\t\t {device_info['device_name']}_ORN\n"
+            f"\t\t\t\t\t {device_info['device_name']}_Markers\n"
+        )
         self.orn_outlet = StreamOutlet(info_orn)
         self.exg_outlet = StreamOutlet(info_exg)
         self.marker_outlet = StreamOutlet(info_marker)
@@ -555,10 +648,8 @@ def __init__(self, device_info, calib_param, notch_freq):
         self._add_filters()
 
     def _add_filters(self):
-        bp_freq = self._device_info['sampling_rate'] / 4 - 1.5, \
-                  self._device_info['sampling_rate'] / 4 + 1.5
-        noise_freq = self._device_info['sampling_rate'] / 4 + 2.5, \
-                     self._device_info['sampling_rate'] / 4 + 5.5
+        bp_freq = self._device_info['sampling_rate'] / 4 - 1.5, self._device_info['sampling_rate'] / 4 + 1.5
+        noise_freq = self._device_info['sampling_rate'] / 4 + 2.5, self._device_info['sampling_rate'] / 4 + 5.5
 
         self._filters['notch'] = ExGFilter(cutoff_freq=self._notch_freq,
                                            filter_type='notch',
@@ -581,7 +672,9 @@ def measure_imp(self, packet):
         temp_packet = self._filters['notch'].apply(input_data=packet, in_place=False)
         self._calib_param['noise_level'] = self._filters['base_noise'].\
             apply(input_data=temp_packet, in_place=False).get_ptp()
-        self._filters['demodulation'].apply(input_data=temp_packet, in_place=True).calculate_impedance(self._calib_param)
+        self._filters['demodulation'].apply(
+            input_data=temp_packet, in_place=True
+        ).calculate_impedance(self._calib_param)
         return temp_packet
 
 
@@ -628,7 +721,7 @@ def _get_rest_orn(self, packet):
     def read_calibre_data(self, device_name):
         config = configparser.ConfigParser()
         calibre_file = user_config_dir(appname="explorepy", appauthor="Mentalab") + "/conf.ini"
-        if os.path.isfile(calibre_file) :
+        if os.path.isfile(calibre_file):
             config.read(calibre_file)
             try:
                 calibre_coef = config[device_name]
@@ -696,16 +789,16 @@ def _map(self, packet):
 
     @staticmethod
     def init_dir():
-        if not (os.path.isfile(user_config_dir(appname="explorepy", appauthor="Mentalab") + "/conf.ini")):
+        if not os.path.isfile(user_config_dir(appname="explorepy", appauthor="Mentalab") + "/conf.ini"):
             os.makedirs(user_config_dir(appname="explorepy", appauthor="Mentalab"), exist_ok=True)
             calibre_out_file = user_config_dir(appname="explorepy", appauthor="Mentalab") + "/conf.ini"
-            with open (calibre_out_file, "w") as f_coef:
+            with open(calibre_out_file, "w") as f_coef:
                 config = configparser.ConfigParser()
-                config['DEFAULT'] = {'description': 'configuration data for Explore devices'}
+                config['DEFAULT'] = {'description': 'configurations for Explorepy'}
                 config.write(f_coef)
                 f_coef.close()
 
-        if not (os.path.isdir(user_cache_dir(appname="explorepy", appauthor="Mentalab"))):
+        if not os.path.isdir(user_cache_dir(appname="explorepy", appauthor="Mentalab")):
             os.makedirs(user_cache_dir(appname="explorepy", appauthor="Mentalab"), exist_ok=True)
 
     @staticmethod
@@ -726,7 +819,7 @@ def calibrate(cache_dir, device_name):
             kx = 0.5 * (mag_set_x[-1] - mag_set_x[0])
             ky = 0.5 * (mag_set_y[-1] - mag_set_y[0])
             kz = 0.5 * (mag_set_z[-1] - mag_set_z[0])
-            k = np.sort(np.array([kx, ky, kz]))
+            # k = np.sort(np.array([kx, ky, kz]))  # Not used here but might be needed in the future
             kx = 1 / kx
             ky = 1 / ky
             kz = 1 / kz
@@ -765,10 +858,7 @@ def check_calibre_data(device_name):
             config.read(calibre_file)
             if config.has_section(device_name):
                 return True
-            else:
-                return False
-        else:
-            return False
+        return False
 
 
 def find_free_port():
@@ -777,8 +867,8 @@ def find_free_port():
     Returns:
         int: Port number
     """
-    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
-        s.bind(('localhost', 0))
-        s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-        port_number = s.getsockname()[1]
+    with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as free_socket:
+        free_socket.bind(('localhost', 0))
+        free_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+        port_number = free_socket.getsockname()[1]
         return port_number
diff --git a/tox.ini b/tox.ini
index b88c46a5..abebc625 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,7 +22,6 @@ passenv =
 usedevelop = false
 deps =
     pytest
-    pytest-travis-fold
     pytest-cov
 commands =
     {posargs:pytest --cov --cov-report=term-missing -vv tests}


Test patch:
diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml
new file mode 100644
index 00000000..538673e3
--- /dev/null
+++ b/.github/workflows/testing.yml
@@ -0,0 +1,36 @@
+name: testing
+on:
+    pull_request:
+        branches: [master]
+jobs:
+    test:
+        strategy:
+            matrix:
+                os: [ubuntu-latest, windows-latest, macos-latest]
+                python: [3.8.10]
+        runs-on: ${{ matrix.os }}
+        timeout-minutes: 10
+        steps:
+            - name: Checkout source repository
+              uses: actions/checkout@v2
+              with:
+                fetch-depth: 0
+                clean: false
+
+            - name: checkout to current branch
+              run: git checkout ${{ env.BRANCH }}
+
+            - name: Install non-python dependencies on Ubuntu
+              if: runner.os == 'Linux'
+              run: |
+                sudo apt-get update -y
+                sudo apt-get install libbluetooth-dev -y
+            - name: Set up Python ${{ matrix.python }}
+              uses: s-weigand/setup-conda@v1
+              with:
+                  python-version: ${{ matrix.python }}
+                  conda-channels: anaconda, conda-forge
+            - run: |
+                conda install -c conda-forge liblsl
+                pip install -e .[test]
+                python -m pytest --import-mode=append
diff --git a/tests/test_explorepy.py b/tests/test_explorepy.py
index ed3594c1..5802ea3e 100644
--- a/tests/test_explorepy.py
+++ b/tests/test_explorepy.py
@@ -1,6 +1,12 @@
+import explorepy
 
-from explorepy.cli import main
 
+explorepy.set_bt_interface('sdk')
 
-def test_main():
-    main([])
+
+class TestMainClass:
+    def test_dummy_1(self):
+        assert 1 == 1
+
+    def test_dummy_2(self):
+        assert 2 == 2