openblt/Host/Source/LibOpenBLT/bindings/python/openblt/lib.py

1206 lines
46 KiB
Python

"""
Implements python wrappers for the OpenBLT host library (LibOpenBLT)
functions.
"""
__docformat__ = 'reStructuredText'
# ***************************************************************************************
# File Name: lib.py
#
# ---------------------------------------------------------------------------------------
# C O P Y R I G H T
# ---------------------------------------------------------------------------------------
# Copyright (c) 2018 by Feaser http://www.feaser.com All rights reserved
#
# ---------------------------------------------------------------------------------------
# L I C E N S E
# ---------------------------------------------------------------------------------------
# This file is part of OpenBLT. OpenBLT is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as published by the Free
# Software Foundation, either version 3 of the License, or (at your option) any later
# version.
#
# OpenBLT is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
# without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
# PURPOSE. See the GNU General Public License for more details.
#
# You have received a copy of the GNU General Public License along with OpenBLT. It
# should be located in ".\Doc\license.html". If not, contact Feaser to obtain a copy.
#
# ***************************************************************************************
# ***************************************************************************************
# Imports
# ***************************************************************************************
import ctypes
import sys
# ***************************************************************************************
# Implementation
# ***************************************************************************************
# Determine the file extension of the share library, which is platform dependent.
if "win" in sys.platform:
sharedLibraryExt = '.dll'
else:
sharedLibraryExt = '.so'
# Initialize the shared library to just its filename without a path. This assumes that
# the LibOpenBLT shared library file and possible other run-time libraries that it
# depends on are located in the directory from where your program runs or somewhere on
# the system's library path. Refer to the section on the OpenBLT Wiki for an overview of
# these run-time libraries:
# https://www.feaser.com/openblt/doku.php?id=manual:libopenblt#run-time_libraries.
sharedLibrary = 'libopenblt' + sharedLibraryExt
# Get a handle to the shared library.
sharedLibraryHandle = ctypes.CDLL(sharedLibrary)
# ***************************************************************************************
# Function import specifications
# ***************************************************************************************
BltVersionGetNumber = None
if hasattr(sharedLibraryHandle, 'BltVersionGetNumber'):
BltVersionGetNumber = sharedLibraryHandle.BltVersionGetNumber
BltVersionGetNumber.argtypes = []
BltVersionGetNumber.restype = ctypes.c_uint32
BltVersionGetString = None
if hasattr(sharedLibraryHandle, 'BltVersionGetString'):
BltVersionGetString = sharedLibraryHandle.BltVersionGetString
BltVersionGetString.argtypes = []
BltVersionGetString.restype = ctypes.c_char_p
BltFirmwareInit = None
if hasattr(sharedLibraryHandle, 'BltFirmwareInit'):
BltFirmwareInit = sharedLibraryHandle.BltFirmwareInit
BltFirmwareInit.argtypes = [ctypes.c_uint32]
BltFirmwareInit.restype = None
BltFirmwareTerminate = None
if hasattr(sharedLibraryHandle, 'BltFirmwareTerminate'):
BltFirmwareTerminate = sharedLibraryHandle.BltFirmwareTerminate
BltFirmwareTerminate.argtypes = []
BltFirmwareTerminate.restype = None
BltFirmwareLoadFromFile = None
if hasattr(sharedLibraryHandle, 'BltFirmwareLoadFromFile'):
BltFirmwareLoadFromFile = sharedLibraryHandle.BltFirmwareLoadFromFile
BltFirmwareLoadFromFile.argtypes = [ctypes.c_char_p, ctypes.c_uint32]
BltFirmwareLoadFromFile.restype = ctypes.c_uint32
BltFirmwareSaveToFile = None
if hasattr(sharedLibraryHandle, 'BltFirmwareSaveToFile'):
BltFirmwareSaveToFile = sharedLibraryHandle.BltFirmwareSaveToFile
BltFirmwareSaveToFile.argtypes = [ctypes.c_char_p]
BltFirmwareSaveToFile.restype = ctypes.c_uint32
BltFirmwareGetSegmentCount = None
if hasattr(sharedLibraryHandle, 'BltFirmwareGetSegmentCount'):
BltFirmwareGetSegmentCount = sharedLibraryHandle.BltFirmwareGetSegmentCount
BltFirmwareGetSegmentCount.argtypes = []
BltFirmwareGetSegmentCount.restype = ctypes.c_uint32
BltFirmwareGetSegment = None
if hasattr(sharedLibraryHandle, 'BltFirmwareGetSegment'):
BltFirmwareGetSegment = sharedLibraryHandle.BltFirmwareGetSegment
BltFirmwareGetSegment.argtypes = [ctypes.c_uint32, ctypes.POINTER(ctypes.c_uint32),
ctypes.POINTER(ctypes.c_uint32)]
BltFirmwareGetSegment.restype = ctypes.POINTER(ctypes.c_uint8)
BltFirmwareAddData = None
if hasattr(sharedLibraryHandle, 'BltFirmwareAddData'):
BltFirmwareAddData = sharedLibraryHandle.BltFirmwareAddData
BltFirmwareAddData.argtypes = [ctypes.c_uint32, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8)]
BltFirmwareAddData.restype = ctypes.c_uint32
BltFirmwareRemoveData = None
if hasattr(sharedLibraryHandle, 'BltFirmwareRemoveData'):
BltFirmwareRemoveData = sharedLibraryHandle.BltFirmwareRemoveData
BltFirmwareRemoveData.argtypes = [ctypes.c_uint32, ctypes.c_uint32]
BltFirmwareRemoveData.restype = ctypes.c_uint32
BltFirmwareClearData = None
if hasattr(sharedLibraryHandle, 'BltFirmwareClearData'):
BltFirmwareClearData = sharedLibraryHandle.BltFirmwareClearData
BltFirmwareClearData.argtypes = []
BltFirmwareClearData.restype = None
BltUtilCrc16Calculate = None
if hasattr(sharedLibraryHandle, 'BltUtilCrc16Calculate'):
BltUtilCrc16Calculate = sharedLibraryHandle.BltUtilCrc16Calculate
BltUtilCrc16Calculate.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_uint32]
BltUtilCrc16Calculate.restype = ctypes.c_uint16
BltUtilCrc32Calculate = None
if hasattr(sharedLibraryHandle, 'BltUtilCrc32Calculate'):
BltUtilCrc32Calculate = sharedLibraryHandle.BltUtilCrc32Calculate
BltUtilCrc32Calculate.argtypes = [ctypes.POINTER(ctypes.c_uint8), ctypes.c_uint32]
BltUtilCrc32Calculate.restype = ctypes.c_uint32
BltUtilTimeGetSystemTime = None
if hasattr(sharedLibraryHandle, 'BltUtilTimeGetSystemTime'):
BltUtilTimeGetSystemTime = sharedLibraryHandle.BltUtilTimeGetSystemTime
BltUtilTimeGetSystemTime.argtypes = []
BltUtilTimeGetSystemTime.restype = ctypes.c_uint32
BltUtilTimeDelayMs = None
if hasattr(sharedLibraryHandle, 'BltUtilTimeDelayMs'):
BltUtilTimeDelayMs = sharedLibraryHandle.BltUtilTimeDelayMs
BltUtilTimeDelayMs.argtypes = [ctypes.c_uint16]
BltUtilTimeDelayMs.restype = None
BltUtilCryptoAes256Encrypt = None
if hasattr(sharedLibraryHandle, 'BltUtilCryptoAes256Encrypt'):
BltUtilCryptoAes256Encrypt = sharedLibraryHandle.BltUtilCryptoAes256Encrypt
BltUtilCryptoAes256Encrypt.argtypes = [ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8)]
BltUtilCryptoAes256Encrypt.restype = ctypes.c_uint32
BltUtilCryptoAes256Decrypt = None
if hasattr(sharedLibraryHandle, 'BltUtilCryptoAes256Decrypt'):
BltUtilCryptoAes256Decrypt = sharedLibraryHandle.BltUtilCryptoAes256Decrypt
BltUtilCryptoAes256Decrypt.argtypes = [ctypes.POINTER(ctypes.c_uint8),
ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8)]
BltUtilCryptoAes256Decrypt.restype = ctypes.c_uint32
BltSessionInit = None
if hasattr(sharedLibraryHandle, 'BltSessionInit'):
BltSessionInit = sharedLibraryHandle.BltSessionInit
BltSessionInit.argtypes = [ctypes.c_uint32, ctypes.POINTER(None), ctypes.c_uint32,
ctypes.POINTER(None)]
BltSessionInit.restype = None
BltSessionTerminate = None
if hasattr(sharedLibraryHandle, 'BltSessionTerminate'):
BltSessionTerminate = sharedLibraryHandle.BltSessionTerminate
BltSessionTerminate.argtypes = []
BltSessionTerminate.restype = None
BltSessionStart = None
if hasattr(sharedLibraryHandle, 'BltSessionStart'):
BltSessionStart = sharedLibraryHandle.BltSessionStart
BltSessionStart.argtypes = []
BltSessionStart.restype = ctypes.c_uint32
BltSessionStop = None
if hasattr(sharedLibraryHandle, 'BltSessionStop'):
BltSessionStop = sharedLibraryHandle.BltSessionStop
BltSessionStop.argtypes = []
BltSessionStop.restype = None
BltSessionClearMemory = None
if hasattr(sharedLibraryHandle, 'BltSessionClearMemory'):
BltSessionClearMemory = sharedLibraryHandle.BltSessionClearMemory
BltSessionClearMemory.argtypes = [ctypes.c_uint32, ctypes.c_uint32]
BltSessionClearMemory.restype = ctypes.c_uint32
BltSessionWriteData = None
if hasattr(sharedLibraryHandle, 'BltSessionWriteData'):
BltSessionWriteData = sharedLibraryHandle.BltSessionWriteData
BltSessionWriteData.argtypes = [ctypes.c_uint32, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8)]
BltSessionWriteData.restype = ctypes.c_uint32
BltSessionReadData = None
if hasattr(sharedLibraryHandle, 'BltSessionReadData'):
BltSessionReadData = sharedLibraryHandle.BltSessionReadData
BltSessionReadData.argtypes = [ctypes.c_uint32, ctypes.c_uint32,
ctypes.POINTER(ctypes.c_uint8)]
# ***************************************************************************************
# Constant declarations
# ***************************************************************************************
BLT_RESULT_OK = 0
BLT_RESULT_ERROR_GENERIC = 1
# ***************************************************************************************
# V E R S I O N I N F O R M A T I O N
# ***************************************************************************************
# ***************************************************************************************
# Functions
# ***************************************************************************************
def version_get_number():
"""
Obtains the version number of the library as an integer. The number has two digits
for major-, minor-, and patch-version. Version 1.05.12 would for example return
10512.
:returns: Library version number as an integer.
:rtype: int
:Example:
::
import openblt
print('LibOpenBLT version:', openblt.version_get_number())
"""
# Initialize the result.
result = 0
# Check if the shared library function could be imported.
if BltVersionGetNumber is not None:
# Call the function in the shared library.
result = BltVersionGetNumber()
# Give the result back to the caller.
return result
def version_get_string():
"""
Obtains the version number of the library as a string. Version 1.05.12 would for
example return "1.05.12".
:returns: Library version number as a string.
:rtype: string
:Example:
::
import openblt
print('LibOpenBLT version:', openblt.version_get_string())
"""
# Initialize the result
result = ''
# Check if the shared library function could be imported.
if BltVersionGetString is not None:
# Call the function in the shared library
result = BltVersionGetString()
# Decode the null terminated character string to a UTF-8 string.
result = result.decode('utf-8')
# Give the result back to the caller.
return result
# ***************************************************************************************
# F I R M W A R E D A T A
# ***************************************************************************************
# ***************************************************************************************
# Constant declarations
# ***************************************************************************************
BLT_FIRMWARE_PARSER_SRECORD = 0
# ***************************************************************************************
# Functions
# ***************************************************************************************
def firmware_init(parser_type=BLT_FIRMWARE_PARSER_SRECORD):
"""
Initializes the firmware data module for a specified firmware file parser.
:param parser_type: The firmware file parser to use in this module. It should be a
BLT_FIRMWARE_PARSER_xxx value.
:Example:
::
import openblt
openblt.firmware_init(openblt.BLT_FIRMWARE_PARSER_SRECORD)
"""
# Check if the shared library function could be imported.
if BltFirmwareInit is not None:
# Call the function in the shared library
BltFirmwareInit(ctypes.c_uint32(parser_type))
def firmware_terminate():
"""
Terminates the firmware data module. Typically called at the end of the program when
the firmware data module is no longer needed.
:Example:
::
import openblt
openblt.firmware_terminate()
"""
# Check if the shared library function could be imported.
if BltFirmwareTerminate is not None:
# Call the function in the shared library
BltFirmwareTerminate()
def firmware_load_from_file(firmware_file, address_offset=0):
"""
Loads firmware data from the specified file using the firmware file parser that was
specified during the initialization of this module.
:param firmware_file: Filename of the firmware file to load.
:param address_offset: Optional memory address offset to add when loading the
firmware data from the file. This is typically only useful when loading
firmware data from a binary formatted firmware file.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
if openblt.firmware_load_from_file('my_firmware.srec', 0) != openblt.BLT_RESULT_OK:
print('[ERROR] Could not open firmware file.')
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltFirmwareLoadFromFile is not None:
# Call the function in the shared library
result = BltFirmwareLoadFromFile(ctypes.c_char_p(firmware_file.encode('utf-8')),
ctypes.c_uint32(address_offset))
# Give the result back to the caller.
return result
def firmware_save_to_file(firmware_file):
"""
Writes firmware data to the specified file using the firmware file parser that was
specified during the initialization of this module.
:param firmware_file: Filename of the firmware file to write to.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
if openblt.firmware_save_to_file('new_firmwware.srec') != openblt.BLT_RESULT_OK:
print('[ERROR] Could not save firmware file.')
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltFirmwareSaveToFile is not None:
# Call the function in the shared library
result = BltFirmwareSaveToFile(ctypes.c_char_p(firmware_file.encode('utf-8')))
# Give the result back to the caller.
return result
def firmware_get_segment_count():
"""
Obtains the number of firmware data segments that are currently present in the
firmware data module.
:returns: The total number of segments.
:rtype: int
:Example:
::
import openblt
print('Number of data segments = ', openblt.firmware_get_segment_count())
"""
# Initialize the result.
result = 0
# Check if the shared library function could be imported.
if BltFirmwareGetSegmentCount is not None:
# Call the function in the shared library
result = BltFirmwareGetSegmentCount()
# Give the result back to the caller.
return result
def firmware_get_segment(idx):
"""
Obtains the contents of the firmware data segment that was specified by the index
parameter. Note that the returned segment data is a copy.
:param idx: The segment index. It should be a value greater or equal to zero and
smaller than the value returned by firmware_get_segment_count.
:returns: Tuple with the segment data list, address and length.
:rtype: tuple
:Example:
::
import openblt
segment_data, segment_address, segment_len = openblt.firmware_get_segment(0)
print('First segment address =', hex(segment_address))
print('First segment length =', segment_len)
print('First Segment data =')
segment_data_str = '\t'
for idx in range(0, segment_len):
segment_data_str += '{:02x}'.format(segment_data[idx]) + ' '
if ((idx+1) % 32) == 0:
print(segment_data_str)
segment_data_str = '\t'
if segment_data_str != '':
print(segment_data_str)
"""
# Initialize the result values.
result_data = []
result_address = int(0)
result_len = int(0)
# Check if the shared library function could be imported.
if BltFirmwareGetSegment is not None:
segment_address = ctypes.c_uint32(0)
segment_len = ctypes.c_uint32(0)
# Call the function in the shared library
segment_data = BltFirmwareGetSegment(ctypes.c_uint32(idx),
ctypes.byref(segment_address),
ctypes.byref(segment_len))
# Store the result values.
result_address = segment_address.value
result_len = segment_len.value
for i in range(result_len):
result_data.append(segment_data[i])
# Give the result back to the caller as a tuple.
return result_data, result_address, result_len
def firmware_add_data(address, len, data):
"""
Adds data to the segments that are currently present in the firmware data module. If
the data overlaps with already existing data, the existing data gets overwritten. The
size of a segment is automatically adjusted or a new segment gets created,
if necessary.
:param address: Base address of the firmware data.
:param len: Number of bytes to add.
:param data: List with data bytes that should be added.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
new_data = [ 0x55, 0xaa, 0x11, 0xee ]
if openblt.firmware_add_data(0x8002000, len(new_data), new_data) != openblt.BLT_RESULT_OK:
print('[ERROR] Could not add firmware data.')
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltFirmwareAddData is not None:
# Convert the list to a c-byte array
new_data_type = ctypes.c_uint8 * len
new_data = new_data_type()
for i in range(0, len):
new_data[i] = ctypes.c_uint8(data[i])
# Call the function in the shared library
result = BltFirmwareAddData(ctypes.c_uint32(address), ctypes.c_uint32(len),
new_data)
# Give the result back to the caller.
return result
def firmware_remove_data(address, len):
"""
Removes data from the segments that are currently present in the firmware data
module. The size of a segment is automatically adjusted or removed, if necessary.
:param address: Base address of the firmware data.
:param len: Number of bytes to remove.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
if openblt.firmware_remove_data(0x8002000, 4) != openblt.BLT_RESULT_OK:
print('[ERROR] Could not remove firmware data.')
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltFirmwareRemoveData is not None:
# Call the function in the shared library
result = BltFirmwareRemoveData(ctypes.c_uint32(address), ctypes.c_uint32(len))
# Give the result back to the caller.
return result
def firmware_clear_data():
"""
Clears all data and segments that are currently present in the firmware data module.
:Example:
::
import openblt
openblt.firmware_clear_data()
"""
# Check if the shared library function could be imported.
if BltFirmwareClearData is not None:
# Call the function in the shared library
BltFirmwareClearData()
# ***************************************************************************************
# G E N E R I C U T I L I T I E S
# ***************************************************************************************
# ***************************************************************************************
# Functions
# ***************************************************************************************
def util_crc16_calculate(data, len):
"""
Calculates a 16-bit CRC value over the specified data.
:param data: List with data bytes over which the CRC16 should be calculated.
:param len: Number of bytes in the list.
:returns: The 16-bit CRC value.
:rtype: int
:Example:
::
import openblt
test_data = [ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 ]
crc16_value = openblt.util_crc16_calculate(test_data, len(test_data))
print('CRC16 value:', crc16_value)
"""
# Initialize the result.
result = 0
# Check if the shared library function could be imported.
if BltUtilCrc16Calculate is not None:
# Convert the list to a c-byte array
src_data_type = ctypes.c_uint8 * len
src_data = src_data_type()
for i in range(0, len):
src_data[i] = ctypes.c_uint8(data[i])
# Call the function in the shared library
result = BltUtilCrc16Calculate(src_data, ctypes.c_uint32(len))
# Give the result back to the caller.
return result
def util_crc32_calculate(data, len):
"""
Calculates a 32-bit CRC value over the specified data.
:param data: List with data bytes over which the CRC32 should be calculated.
:param len: Number of bytes in the list.
:returns: The 32-bit CRC value.
:rtype: int
:Example:
::
import openblt
test_data = [ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80 ]
crc32_value = openblt.util_crc32_calculate(test_data, len(test_data))
print('CRC32 value:', crc32_value)
"""
# Initialize the result.
result = 0
# Check if the shared library function could be imported.
if BltUtilCrc32Calculate is not None:
# Convert the list to a c-byte array
src_data_type = ctypes.c_uint8 * len
src_data = src_data_type()
for i in range(0, len):
src_data[i] = ctypes.c_uint8(data[i])
# Call the function in the shared library
result = BltUtilCrc32Calculate(src_data, ctypes.c_uint32(len))
# Give the result back to the caller.
return result
def util_time_get_system_time():
"""
Get the system time in milliseconds.
:returns: Time in milliseconds.
:rtype: int
:Example:
::
import openblt
print('Current system time:', openblt.util_time_get_system_time(), 'ms')
"""
# Initialize the result.
result = 0
# Check if the shared library function could be imported.
if BltUtilTimeGetSystemTime is not None:
# Call the function in the shared library.
result = BltUtilTimeGetSystemTime()
# Give the result back to the caller.
return result
def util_time_delay_ms(delay):
"""
Performs a delay of the specified amount of milliseconds.
:param delay: Delay time in milliseconds.
:Example:
::
import openblt
openblt.util_time_delay_ms(1000)
"""
# Check if the shared library function could be imported.
if BltUtilTimeDelayMs is not None:
# Call the function in the shared library
BltUtilTimeDelayMs(ctypes.c_uint16(delay))
def util_crypto_aes256_encrypt(data, len, key):
"""
Encrypts the len-bytes in the specified data list, using the specified 256-bit
(32 bytes) key. The results are written back into the same list.
:param data: List with data bytes to encrypt. The encrypted bytes are stored in the
same list.
:param len: The number of bytes in the data list to encrypt. It must be a multiple
of 16, as this is the AES256 minimal block size.
:param key: The 256-bit encryption key as a list with 32 bytes.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
crypto_key = [0xCB, 0x81, 0xA5, 0x9A, 0x80, 0x2C, 0x98, 0x1C,
0xF8, 0x8C, 0x5D, 0x59, 0x1B, 0x48, 0x5C, 0xAD,
0xE5, 0xC0, 0xD5, 0x98, 0xD8, 0x89, 0xD4, 0xC9,
0xC4, 0x66, 0x4B, 0x09, 0x2D, 0x19, 0xF8, 0xF6]
crypto_data = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F]
print('Original data =')
crypto_data_str = '\t'
for byte_value in crypto_data:
crypto_data_str += '{:02x}'.format(byte_value) + ' '
print(crypto_data_str)
openblt.util_crypto_aes256_encrypt(crypto_data, 16, crypto_key)
print('Encrypted data =')
crypto_data_str = '\t'
for byte_value in crypto_data:
crypto_data_str += '{:02x}'.format(byte_value) + ' '
print(crypto_data_str)
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltUtilCryptoAes256Encrypt is not None:
# Convert the list with source data to a c-byte array.
src_data_type = ctypes.c_uint8 * len
src_data = src_data_type()
for i in range(0, len):
src_data[i] = ctypes.c_uint8(data[i])
# Convert the list with key data to a c-byte array.
key_data_type = ctypes.c_uint8 * 32
key_data = key_data_type()
for i in range(0, 32):
key_data[i] = ctypes.c_uint8(key[i])
# Call the function in the shared library.
result = BltUtilCryptoAes256Encrypt(src_data, ctypes.c_uint32(len), key_data)
# Now write the encrypted data back into the list
if result == BLT_RESULT_OK:
for i in range(0, len):
data[i] = src_data[i]
# Give the result back to the caller.
return result
def util_crypto_aes256_decrypt(data, len, key):
"""
Decrypts the len-bytes in the specified data list, using the specified 256-bit
(32 bytes) key. The results are written back into the same list.
:param data: List with data bytes to decrypt. The decrypted bytes are stored in the
same list.
:param len: The number of bytes in the data list to decrypt. It must be a multiple
of 16, as this is the AES256 minimal block size.
:param key: The 256-bit decryption key as a list with 32 bytes.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
crypto_key = [0xCB, 0x81, 0xA5, 0x9A, 0x80, 0x2C, 0x98, 0x1C,
0xF8, 0x8C, 0x5D, 0x59, 0x1B, 0x48, 0x5C, 0xAD,
0xE5, 0xC0, 0xD5, 0x98, 0xD8, 0x89, 0xD4, 0xC9,
0xC4, 0x66, 0x4B, 0x09, 0x2D, 0x19, 0xF8, 0xF6]
crypto_data = [0x34, 0x7A, 0xC9, 0x82, 0x83, 0xB7, 0x8C, 0xAA,
0x14, 0x39, 0x6E, 0xCF, 0x10, 0xA4, 0xAA, 0x96]
openblt.util_crypto_aes256_decrypt(crypto_data, 16, crypto_key)
print('Decrypted data =')
crypto_data_str = '\t'
for byte_value in crypto_data:
crypto_data_str += '{:02x}'.format(byte_value) + ' '
print(crypto_data_str)
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltUtilCryptoAes256Decrypt is not None:
# Convert the list with source data to a c-byte array.
src_data_type = ctypes.c_uint8 * len
src_data = src_data_type()
for i in range(0, len):
src_data[i] = ctypes.c_uint8(data[i])
# Convert the list with key data to a c-byte array.
key_data_type = ctypes.c_uint8 * 32
key_data = key_data_type()
for i in range(0, 32):
key_data[i] = ctypes.c_uint8(key[i])
# Call the function in the shared library.
result = BltUtilCryptoAes256Decrypt(src_data, ctypes.c_uint32(len), key_data)
# Now write the decrypted data back into the list
if result == BLT_RESULT_OK:
for i in range(0, len):
data[i] = src_data[i]
# Give the result back to the caller.
return result
# ***************************************************************************************
# S E S S I O N / T R A N S P O R T L A Y E R S
# ***************************************************************************************
# ***************************************************************************************
# Constant declarations
# ***************************************************************************************
BLT_SESSION_XCP_V10 = 0
BLT_TRANSPORT_XCP_V10_RS232 = 0
BLT_TRANSPORT_XCP_V10_CAN = 1
BLT_TRANSPORT_XCP_V10_USB = 2
BLT_TRANSPORT_XCP_V10_NET = 3
# ***************************************************************************************
# Classes
# ***************************************************************************************
class BltSessionSettingsXcpV10:
"""
Class with the layout of the XCP version 1.0 session settings.
"""
def __init__(self):
"""
Class constructor.
"""
# Set default values for instance variables.
self.timeoutT1 = 1000 # Command response timeout in milliseconds.
self.timeoutT3 = 2000 # Start programming timeout in milliseconds.
self.timeoutT4 = 10000 # Erase memory timeout in milliseonds.
self.timeoutT5 = 1000 # Program memory and reset timeout in milliseconds.
self.timeoutT7 = 2000 # Busy wait timer timeout in milliseconds.
self.seedKeyFile = '' # Seed/key algorithm library filename.
self.connectMode = 0 # Connection mode parameter in XCP connect command.
class BltTransportSettingsXcpV10Rs232:
"""
Class with the layout of the XCP version 1.0 RS232 transport layer settings. The
portName field is platform dependent. On Linux based systems this should be the
filename of the tty-device, such as "/dev/tty0". On Windows based systems it should
be the name of the COM-port, such as "COM1".
"""
def __init__(self):
"""
Class constructor.
"""
# Set default values for instance variables.
self.portName = '' # Communication port name such as /dev/tty0.
self.baudrate = 57600 # Communication speed in bits/sec.
class BltTransportSettingsXcpV10Can:
"""
Class with the layout of the XCP version 1.0 CAN transport layer settings. The
deviceName field is platform dependent. On Linux based systems this should be the
socketCAN interface name such as "can0". The terminal command "ip addr" can be issued
to view a list of interfaces that are up and available. Under Linux it is assumed
that the socketCAN interface is already configured on the system, before using the
OpenBLT library. When baudrate is configured when bringing up the system, so the
baudrate field in this structure is don't care when using the library on a Linux was
system. On Windows based systems, the device name is a name that is pre-defined by
this library for the supported CAN adapters. The device name should be one of the
following: "peak_pcanusb", "kvaser_leaflight", or "lawicel_canusb". Field use
extended is a boolean field. When set to 0, the specified transmitId and receiveId
are assumed to be 11-bit standard CAN identifier. It the field is 1, these
identifiers are assumed to be 29-bit extended CAN identifiers.
"""
def __init__(self):
"""
Class constructor.
"""
# Set default values for instance variables.
self.deviceName = '' # Device name such as can0, peak_pcanusb etc.
self.deviceChannel = 0 # Channel on the device to use.
self.baudrate = 500000 # Communication speed in bits/sec.
self.transmitId = 0x667 # Transmit CAN identifier.
self.receiveId = 0x7E1 # Receive CAN identifier.
self.useExtended = 0 # Boolean to configure 29-bit CAN identifiers.
class BltTransportSettingsXcpV10Net:
"""
Class with the layout of the XCP version 1.0 NET transport layer settings. The
address field can be set to either the IP address or the hostname, such as
"192.168.178.23" or "mymicro.mydomain.com". The port should be set to the TCP port
number that the bootloader target listens on.
"""
def __init__(self):
"""
Class constructor.
"""
# Set default values for instance variables.
self.address = '' # Target IP-address or hostname on the network.
self.port = 1000 # TCP port to use.
# ***************************************************************************************
# Functions
# ***************************************************************************************
def session_init(session_type, session_settings, transport_type, transport_settings):
"""
Initializes the firmware update session for a specific communication protocol and
transport layer. This function is typically called once at the start of the firmware
update.
:param session_type: The communication protocol to use for this session. It should
be a BLT_SESSION_xxx value.
:param session_settings: Instance of class BltSessionSettingsXxx with communication
protocol specific settings.
:param transport_type: The transport layer to use for the specified communication
protocol. It should be a BLT_TRANSPORT_xxx value.
:param transport_settings: Instance of class BltTransportSettingsXxx with transport
layer specific settings.
:Example:
::
import openblt
session_type = openblt.BLT_SESSION_XCP_V10
session_settings = openblt.BltSessionSettingsXcpV10()
session_settings.timeoutT1 = 1000
session_settings.timeoutT3 = 2000
session_settings.timeoutT4 = 10000
session_settings.timeoutT5 = 1000
session_settings.timeoutT7 = 2000
session_settings.seedKeyFile = ''
session_settings.connectMode = 0
transport_type = openblt.BLT_TRANSPORT_XCP_V10_RS232
transport_settings = openblt.BltTransportSettingsXcpV10Rs232()
transport_settings.portName = '/dev/ttyACM0'
transport_settings.baudrate = 57600
openblt.session_init(session_type, session_settings,
transport_type, transport_settings)
"""
class struct_t_blt_session_settings_xcp_v10(ctypes.Structure):
"""
C-types structure for mapping to BltSessionSettingsXcpV10
"""
_fields_ = [('timeoutT1', ctypes.c_uint16),
('timeoutT3', ctypes.c_uint16),
('timeoutT4', ctypes.c_uint16),
('timeoutT5', ctypes.c_uint16),
('timeoutT7', ctypes.c_uint16),
('seedKeyFile', ctypes.c_char_p),
('connectMode', ctypes.c_uint8)]
class struct_t_blt_transport_settings_xcp_v10_rs232(ctypes.Structure):
"""
C-types structure for mapping to BltTransportSettingsXcpV10Rs232
"""
_fields_ = [('portName', ctypes.c_char_p),
('baudrate', ctypes.c_uint32)]
class struct_t_blt_transport_settings_xcp_v10_can(ctypes.Structure):
"""
C-types structure for mapping to BltTransportSettingsXcpV10Can
"""
_fields_ = [('deviceName', ctypes.c_char_p),
('deviceChannel', ctypes.c_uint32),
('baudrate', ctypes.c_uint32),
('transmitId', ctypes.c_uint32),
('receiveId', ctypes.c_uint32),
('useExtended', ctypes.c_uint32)]
class struct_t_blt_transport_settings_xcp_v10_net(ctypes.Structure):
"""
C-types structure for mapping to BltTransportSettingsXcpV10Net
"""
_fields_ = [('address', ctypes.c_char_p),
('port', ctypes.c_uint16)]
# Convert session settings to the correct c-types structure.
session_settings_struct = None
if session_type == BLT_SESSION_XCP_V10:
session_settings_struct = struct_t_blt_session_settings_xcp_v10()
session_settings_struct.timeoutT1 = ctypes.c_uint16(session_settings.timeoutT1)
session_settings_struct.timeoutT3 = ctypes.c_uint16(session_settings.timeoutT3)
session_settings_struct.timeoutT4 = ctypes.c_uint16(session_settings.timeoutT4)
session_settings_struct.timeoutT5 = ctypes.c_uint16(session_settings.timeoutT5)
session_settings_struct.timeoutT7 = ctypes.c_uint16(session_settings.timeoutT7)
session_settings_struct.seedKeyFile = \
ctypes.c_char_p(session_settings.seedKeyFile.encode('utf-8'))
session_settings_struct.connectMode = \
ctypes.c_uint8(session_settings.connectMode)
# Convert transport settings to the correct c-types structure.
transport_settings_struct = None
if transport_type == BLT_TRANSPORT_XCP_V10_RS232:
transport_settings_struct = struct_t_blt_transport_settings_xcp_v10_rs232()
transport_settings_struct.portName = \
ctypes.c_char_p(transport_settings.portName.encode('utf-8'))
transport_settings_struct.baudrate = ctypes.c_uint32(transport_settings.baudrate)
elif transport_type == BLT_TRANSPORT_XCP_V10_CAN:
transport_settings_struct = struct_t_blt_transport_settings_xcp_v10_can()
transport_settings_struct.deviceName = \
ctypes.c_char_p(transport_settings.deviceName.encode('utf-8'))
transport_settings_struct.deviceChannel = \
ctypes.c_uint32(transport_settings.deviceChannel)
transport_settings_struct.baudrate = \
ctypes.c_uint32(transport_settings.baudrate)
transport_settings_struct.transmitId = \
ctypes.c_uint32(transport_settings.transmitId)
transport_settings_struct.receiveId = \
ctypes.c_uint32(transport_settings.receiveId)
transport_settings_struct.useExtended = \
ctypes.c_uint32(transport_settings.useExtended)
elif transport_type == BLT_TRANSPORT_XCP_V10_NET:
transport_settings_struct = struct_t_blt_transport_settings_xcp_v10_net()
transport_settings_struct.address = \
ctypes.c_char_p(transport_settings.address.encode('utf-8'))
transport_settings_struct.port = \
ctypes.c_uint16(transport_settings.port)
# Check if the shared library function could be imported.
if BltSessionInit is not None:
# Prepare pointer parameters
if session_settings_struct == None:
session_settings_struct_ptr = None
else:
session_settings_struct_ptr = ctypes.byref(session_settings_struct)
if transport_settings_struct == None:
transport_settings_struct_ptr = None
else:
transport_settings_struct_ptr = ctypes.byref(transport_settings_struct)
# Call the function in the shared library
BltSessionInit(ctypes.c_uint32(session_type),
session_settings_struct_ptr,
ctypes.c_uint32(transport_type),
transport_settings_struct_ptr)
def session_terminate():
"""
Terminates the firmware update session. This function is typically called once at the
end of the firmware update.
:Example:
::
import openblt
openblt.session_terminate()
"""
# Check if the shared library function could be imported.
if BltSessionTerminate is not None:
# Call the function in the shared library
BltSessionTerminate()
def session_start():
"""
Starts the firmware update session. This is were the library attempts to activate and
connect with the bootloader running on the target, through the transport layer that
was specified during the session's initialization.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
if openblt.session_start() != openblt.BLT_RESULT_OK:
print('[ERROR] Could not start the session.')
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltSessionStart is not None:
# Call the function in the shared library
result = BltSessionStart()
# Give the result back to the caller.
return result
def session_stop():
"""
Stops the firmware update session. This is there the library disconnects the
transport layer as well.
:Example:
::
import openblt
openblt.session_stop()
"""
# Check if the shared library function could be imported.
if BltSessionStop is not None:
# Call the function in the shared library
BltSessionStop()
def session_clear_memory(address, len):
"""
Requests the target to erase the specified range of memory on the target. Note that
the target automatically aligns this to the erasable memory block sizes. This
typically results in more memory being erased than the range that was specified here.
Refer to the target implementation for details.
:param address: The starting memory address for the erase operation.
:param len: The total number of bytes to erase from memory.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
if openblt.session_clear_memory(0x8002000, 1024) != openblt.BLT_RESULT_OK:
print('[ERROR] Could not erase memory.')
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltSessionClearMemory is not None:
# Call the function in the shared library
result = BltSessionClearMemory(ctypes.c_uint32(address), ctypes.c_uint32(len))
# Give the result back to the caller.
return result
def session_write_data(address, len, data):
"""
Requests the target to program the specified data to memory. Note that it is the
responsibility of the application to make sure the memory range was erased
beforehand.
:param address: The starting memory address for the write operation.
:param len: The number of bytes in the data buffer that should be written.
:param data: List with data bytes that should be written.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
new_data = [ 0x11, 0x22, 0x33, 0x44 ]
if openblt.session_write_data(0x8002000, len(new_data), new_data) != openblt.BLT_RESULT_OK:
print('[ERROR] Could not write data.')
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltSessionWriteData is not None:
# Convert the list to a c-byte array
new_data_type = ctypes.c_uint8 * len
new_data = new_data_type()
for i in range(0, len):
new_data[i] = ctypes.c_uint8(data[i])
# Call the function in the shared library
result = BltSessionWriteData(ctypes.c_uint32(address), ctypes.c_uint32(len),
new_data)
# Give the result back to the caller.
return result
def session_read_data(address, len, data):
"""
Requests the target to upload the specified range from memory and store its contents
in the specified data buffer.
:param address: The starting memory address for the read operation.
:param len: The number of bytes to upload from the target and store in the data
buffer.
:param data: List where the uploaded data bytes should be stored.
:returns: BLT_RESULT_OK if successful, BLT_RESULT_ERROR_xxx otherwise.
:rtype: int
:Example:
::
import openblt
read_data = []
openblt.session_read_data(0x08002800, 16, read_data)
print('Read data =')
read_data_str = '\t'
for byte_value in read_data:
read_data_str += '{:02x}'.format(byte_value) + ' '
print(read_data_str)
"""
# Initialize the result.
result = BLT_RESULT_ERROR_GENERIC
# Check if the shared library function could be imported.
if BltSessionReadData is not None:
# Create c-byte array for storing the uploaded byte values.
upload_data_type = ctypes.c_uint8 * len
upload_data = upload_data_type()
# Call the function in the shared library.
result = BltSessionReadData(ctypes.c_uint32(address), ctypes.c_uint32(len),
upload_data)
# Copy the uploaded data byte values to the data list provided by the caller.
for i in range(len):
data.append(upload_data[i])
# Give the result back to the caller.
return result
# ********************************* end of lib.py ***************************************