################################################################################
# COPYRIGHT(c) 2018 STMicroelectronics #
# #
# Redistribution and use in source and binary forms, with or without #
# modification, are permitted provided that the following conditions are met: #
# 1. Redistributions of source code must retain the above copyright notice, #
# this list of conditions and the following disclaimer. #
# 2. Redistributions in binary form must reproduce the above copyright #
# notice, this list of conditions and the following disclaimer in the #
# documentation and/or other materials provided with the distribution. #
# 3. Neither the name of STMicroelectronics nor the names of its #
# contributors may be used to endorse or promote products derived from #
# this software without specific prior written permission. #
# #
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" #
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE #
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE #
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE #
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR #
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF #
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS #
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN #
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) #
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE #
# POSSIBILITY OF SUCH DAMAGE. #
################################################################################
"""firmware_upgrade
The firmware_upgrade module is responsible for managing the upgrading process of
devices' firmware via Bluetooth Low Energy (BLE).
"""
# IMPORT
import sys
import os
from enum import Enum
from abc import ABCMeta
from abc import abstractmethod
from concurrent.futures import ThreadPoolExecutor
from blue_st_sdk.utils.python_utils import lock
# CLASSES
[docs]class FirmwareUpgrade(object):
"""Class to handle the firmware upgrade capability for a device running the
BlueST Protocol.
"""
_NUMBER_OF_THREADS = 5
"""Number of threads to be used to notify the listeners."""
[docs] def __init__(self):
"""Constructor."""
self._thread_pool = ThreadPoolExecutor(FirmwareUpgrade._NUMBER_OF_THREADS)
"""Pool of thread used to notify the listeners."""
self._listeners = []
"""List of listeners to the node changes.
It is a thread safe list, so a listener can subscribe itself through a
callback."""
[docs] def add_listener(self, listener):
"""Add a listener.
Args:
listener (:class:`blue_st_sdk.firmware_upgrade.utils.firmware_upgrade.FirmwareUpgradeListener`):
Listener to be added.
"""
if listener is not None:
with lock(self):
if not listener in self._listeners:
self._listeners.append(listener)
[docs] def remove_listener(self, listener):
"""Remove a listener.
Args:
listener (:class:`blue_st_sdk.firmware_upgrade.utils.firmware_upgrade.FirmwareUpgradeListener`):
Listener to be removed.
"""
if listener is not None:
with lock(self):
if listener in self._listeners:
self._listeners.remove(listener)
[docs] @abstractmethod
def get_console(self, node):
"""Get an instance of this class.
Args:
node (:class:`blue_st_sdk.node.Node`): Node whose firmware has to be
updated.
Returns:
:class:`blue_st_sdk.firmware_upgrade.firmware_upgrade.FirmwareUpgrade`:
An instance of this class if the given node implements the BlueST
protocol, "None" otherwise.
Raises:
:exc:`NotImplementedError` if the method has not been implemented.
"""
raise NotImplementedError('You must implement "get_console()" to '
'use the "FirmwareUpgrade" class.')
[docs] @abstractmethod
def upgrade_firmware(self, firmware_file):
"""Upgrade the firmware onto the device assiciated to the debug console.
The firmware is loaded starting from the address "0x0804000".
Args:
firmware_file (:class:`blue_st_sdk.firmware_upgrade.utils.firmware_file.FirmwareFile`):
Firmware file.
Raises:
:exc:`NotImplementedError` if the method has not been implemented.
:exc:`OSError` if the file is not found or is inaccessible.
:exc:`ValueError` if the firmware file can not be read properly.
Returns:
bool: True if the upload starts correctly, False otherwise.
"""
raise NotImplementedError('You must implement "upgrade_firmware()" to '
'use the "FirmwareUpgrade" class.')
[docs]class FirmwareUpgradeError(Enum):
"""Class with different errors that may happen when upgrading the
firmware"""
# Error fired when the CRC computed at node side does not correspond to
# the one computed at gateway side.
# This may happen when there errors during the transmission.
CORRUPTED_FILE_ERROR = 0
# Error fired when is not possible to upload all the file.
TRANSMISSION_ERROR = 1
# Error fired when it is not possible to open the file.
INVALID_FIRMWARE_ERROR = 2
# INTERFACES
[docs]class FirmwareUpgradeListener(object):
"""Interface used by the :class:`blue_st_sdk.firmware_upgrade.firmware_upgrade.FirmwareUpgrade`
class to notify changes of the firmware uprgade process.
"""
__metaclass__ = ABCMeta
[docs] @abstractmethod
def on_upgrade_firmware_complete(self, debug_console, firmware_file, \
bytes_sent):
"""To be called whenever the firmware has been upgraded correctly.
Args:
debug_console (:class:`blue_st_sdk.debug_console.DebugConsole`):
Debug console.
firmware_file (:class:`blue_st_sdk.firmware_upgrade.utils.firmware_file.FirmwareFile`):
Firmware file.
bytes_sent (int): Data sent in bytes.
Raises:
:exc:`NotImplementedError` if the method has not been implemented.
"""
raise NotImplementedError('You must implement '
'"on_upgrade_firmware_complete()" to '
'use the "FirmwareUpgradeListener" class.')
[docs] @abstractmethod
def on_upgrade_firmware_error(self, debug_console, firmware_file, error):
"""To be called whenever there is an error in upgrading the firmware.
Args:
debug_console (:class:`blue_st_sdk.debug_console.DebugConsole`):
Debug console.
firmware_file (:class:`blue_st_sdk.firmware_upgrade.utils.firmware_file.FirmwareFile`):
Firmware file.
error (:class:`blue_st_sdk.firmware_upgrade.firmware_upgrade.FirmwareUpgradeError`):
Error code.
Raises:
:exc:`NotImplementedError` if the method has not been implemented.
"""
raise NotImplementedError('You must implement '
'"on_upgrade_firmware_error()" to '
'use the "FirmwareUpgradeListener" class.')
[docs] @abstractmethod
def on_upgrade_firmware_progress(self, debug_console, firmware_file, bytes_sent):
"""To be called whenever there is an update in upgrading the firmware,
i.e. a block of data has been correctly sent and it is possible to send
a new one.
Args:
debug_console (:class:`blue_st_sdk.debug_console.DebugConsole`):
Debug console.
firmware_file (:class:`blue_st_sdk.firmware_upgrade.utils.firmware_file.FirmwareFile`):
Firmware file.
bytes_sent (int): Data sent in bytes.
bytes_to_send (int): Data to send in bytes.
Raises:
:exc:`NotImplementedError` if the method has not been implemented.
"""
raise NotImplementedError('You must implement '
'"on_upgrade_firmware_progress()" to '
'use the "FirmwareUpgradeListener" class.')