Scrutiny Firmware Description (SFD)#

A Scrutiny Firmware Description (SFD) is a file that’s generated during the firmware’s build phase. This file includes:

  1. The device’s static and global variables, which are identified from the debug symbols (including address, size, type, endianness)

  2. A Firmware ID, which is used to match the SFD with the corresponding firmware

  3. The metadata about the firmware, such as its name, project version, author, build date, etc.

  4. Aliases definitions

The SFD must be installed on the server using one of the following method :

  • Through the CLI, using the install-sfd command. The command must be run on the server. (Example: scrutiny install-sfd my_file.sfd)

  • Through the SDK, using init_sfd_upload()

  • Through the GUI. The GUI uses the SDK to upload the SFD file to the server

When a device connects, the server will automatically load the appropriate SFD based on the firmware ID that the device broadcasts.


ScrutinyClient.get_installed_sfds()[source]#

Gets the list of Scrutiny Firmware Description file installed on the server

Raises:

OperationFailure – Failed to get the SFD list

Returns:

A dictionary mapping firmware IDs (hash) to a SFDInfo structure

Return type:

Dict[str, SFDInfo]


ScrutinyClient.uninstall_sfds(firmware_id_list)[source]#

Uninstall a list of Scrutiny Firmware Description (SFD) from the server.

Parameters:

firmware_id_list (List[str]) – The list of firmware ID. Should be an 128bits hexadecimal string (32 chars)

Raises:
  • OperationFailure – Failed to uninstall the given SFDs

  • TypeError – Given parameter not of the expected type

Return type:

None


ScrutinyClient.download_sfd(firmware_id)[source]#

Download a Scrutiny Fiimware Description file from the server

Parameters:

firmware_id (str) – A 32 char hex string that matches the wanted SFD firmware ID

Returns:

A handle on the request that gives the status of the download and can be waited on

Raises:

TypeError – Given parameter not of the expected type

Return type:

SFDDownloadRequest


ScrutinyClient.init_sfd_upload(filepath)[source]#

Initialize the upload and isntall process of a Scrutiny Firmware Description (SFD) file to the server. Calling this method will not transfer the data: calling SFDUploadRequest.start() on the returned object is required to start the file transfer.

Parameters:

filepath (str | Path) – The path to the SFD file to upload and install

Returns:

A handle on the request that gives the status of the uplaod and can be waited on

Raises:
  • TypeError – Given parameter not of the expected type

  • ValueError – Given file is invalid or too big

  • FileNotFoundError – If filepath does not point to an existing file.

  • OperationFailure – Failed to initialize the upload, the server may have denied it

Return type:

SFDUploadRequest


class scrutiny.sdk.SFDInfo[source]#

(Immutable struct) Represent a Scrutiny Firmware Description

firmware_id: str#

Unique firmware hash

filesize: int | None#

The size of the SFD file in the server storage. None if not available

metadata: SFDMetadata | None#

The firmware metadata embedded in the Scrutiny Firmware Description file if available. None if no metadata has been added to the SFD


class scrutiny.sdk.SFDMetadata[source]#

(Immutable struct) All the metadata associated with a Scrutiny Firmware Description

project_name: str | None#

Name of the project. None if not available

author: str | None#

The author of this firmware. None if not available

version: str | None#

The version string of this firmware. None if not available

generation_info: SFDGenerationInfo#

Metadata regarding the creation environment of the SFD file.


class scrutiny.sdk.SFDGenerationInfo[source]#

(Immutable struct) Metadata relative to the generation of the SFD

timestamp: datetime | None#

Date/time at which the SFD has been created. None if not available

python_version: str | None#

Python version with which the SFD has been created. None if not available

scrutiny_version: str | None#

Scrutiny version with which the SFD has been created. None if not available

system_type: str | None#

Type of system on which the SFD has been created. Value given by Python platform.system(). None if not available


class scrutiny.sdk.client.SFDDownloadRequest[source]#

Represents a pending SFD (Scrutiny Firmware Description) file download request. It can be used to wait for completion and get the file data.

property received_count: int#

Amount of bytes received so far

property firmware_id: str#

The firmware ID of the SFD being downloaded

cancel()[source]#

Cancel the request and wake up any thread that called wait_for_completion

Raises:

OperationFailure – If the request is no longer tracked by the client.

Return type:

None

get()[source]#

Return the downloaded SFD (Scrutiny Firmware Description) data. Data is available once is_success=True. One can call wait_for_completion to wait for all the data to be received.

Raises:

InvalidValueError – If the data is not fully downloaded.

Return type:

bytes

get_progress()[source]#

Returns a number between 0 and 1 indicating the download percentage being received

Return type:

float

property completed: bool#

Indicates whether the request has completed or not

property completion_datetime: datetime | None#

The time at which the request has been completed. None if not completed yet

property failure_reason: str#

When the request failed, this property contains the reason for the failure. Empty string if not completed or succeeded

property is_success: bool#

Indicates whether the request has successfully completed or not

wait_for_completion(timeout=None)#

Wait for the request to complete

Params timeout:

Maximum wait time in seconds. Waits forever if None

Raises:
  • TimeoutException – If the request does not complete in less than the specified timeout value

  • OperationFailure – If an error happened that prevented the request to successfully complete

Parameters:

timeout (float | None) –

Return type:

None


class scrutiny.sdk.client.SFDUploadRequest[source]#

Represents a pending SFD (Scrutiny Firmware Description) file upload request. It can be used to wait for completion

property firmware_id: str#

Firmware ID of the SFD being uploaded

property abs_filepath: str#

Gives the absolute path the file being uploaded

property will_overwrite: bool#

Indicate if the request will overwrite an existing SFD installed on the server.

get_sfd_info()[source]#

Reads the SFDInfo structure returned by the server after a successful upload.

Raises:

InvalidValueError – If called while the request is not successful

Returns:

The uploaded file SFDInfo

Return type:

SFDInfo

start()[source]#

Request the client to start uploading the file content.

Raises:

OperationFailure – If the upload request is no longer tracked by the client.

Return type:

None

cancel()[source]#

Stop uploading to the server.

Raises:

OperationFailure – If the upload request is no longer tracked by the client.

Return type:

None

get_progress()[source]#

Returns a number between 0 and 1 indicating the upload percentage being acknowledged by the server

Return type:

float


Examples#

Download an SFD from the server and save it to a file

from scrutiny.sdk.client import ScrutinyClient
client = ScrutinyClient()
with client.connect("localhost", 8765):
    req = client.download_sfd("0123456789ABCDEF0123456789ABCDEF")   # Firmware ID
    print("Downloading SFD")
    req.wait_for_completion(timeout=10)  # Blocking call. A different thread could query req.get_progress()
    filename = "myfile_sfd"
    with open(filename, 'wb') as f:
        f.write(req.get())
    print(f"File downloaded to {filename}")

Upload and SFD to the server and install it

from scrutiny.sdk.client import ScrutinyClient
client = ScrutinyClient()
with client.connect("localhost", 8765):
    req = client.init_sfd_upload("my_file.sfd")
    if req.will_overwrite:
        req.cancel()
        # Could ask for overwrite confirmation
        print("An SFD with the same firmware ID exists on the server. Cowardly not installing")
    else:
        req.start()
        print("Uploading SFD...")
        req.wait_for_completion(timeout=10)  # Blocking call. A different thread could query req.get_progress()
        print("SFD Uploaded and installed on the server!")