1#!/usr/bin/python
2"""
3SPDX-License-Identifier: Apache-2.0
4Copyright (c) 2021 STMicroelectronics.
5This script updates ble library
6"""
7
8import sys
9import os
10import shutil
11import subprocess
12from pathlib import Path
13import logging
14from common_utils import common_utils
15
16include_dir = ["stm32wb/hci"]
17
18file_list = [
19    "Middlewares/ST/STM32_WPAN/ble/core/ble_bufsize.h",
20    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/hw.h",
21    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c",
22    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.h",
23    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.h",
24    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/mbox_def.h",
25    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl_if.c",
26    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl.c",
27    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl.h",
28    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl.h",
29    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c",
30    "Middlewares/ST/STM32_WPAN/stm32_wpan_common.h",
31    "Middlewares/ST/STM32_WPAN/utilities/dbg_trace.h",
32    "Middlewares/ST/STM32_WPAN/utilities/stm_list.c",
33    "Middlewares/ST/STM32_WPAN/utilities/stm_list.h",
34    "Middlewares/ST/STM32_WPAN/utilities/utilities_common.h",
35    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/Core/Inc/app_common.h",
36    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/Core/Inc/app_conf.h",
37    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/Core/Inc/hw_if.h",
38    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/STM32_WPAN/Target/"
39    + "hw_ipcc.c",
40    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/STM32_WPAN/App/"
41    + "tl_dbg_conf.h",
42]
43
44
45def os_cmd(cmd, cwd=None, shell=False):
46    """Execute a command with subprocess.check_call()
47    Args:
48        cmd: string command to execute.
49        cwd: directory where to run command
50        shell: boolean to enable command interpretation by the shell
51
52    Returns:
53        return the returncode of the command after execution.
54    """
55    logging.debug("%s", f"{str(cmd)}      cwd:{str(cwd)}")
56
57    return subprocess.check_call(
58        cmd,
59        shell=shell,
60        cwd=cwd,
61        stdout=subprocess.DEVNULL,
62        stderr=subprocess.DEVNULL,
63    )
64
65
66def copy_hci_files(src_repo_path, dest_lib_path):
67    """Copy sources files from Cube Firmware to zephyr"""
68    # remove existing *.c and *.h files
69    hci_path = Path(dest_lib_path / "stm32wb" / "hci")
70    if hci_path.exists():
71        for item in os.listdir(hci_path):
72            if item.endswith(".c") or item.endswith(".h"):
73                os.remove(hci_path / item)
74
75    for file in file_list:
76        file_path = Path(src_repo_path / file)
77        file_name = file_path.name
78        if file_path.exists:
79            # copy each file to destination
80            if not Path(dest_lib_path / "stm32wb" / "hci" / file_name).parent.exists():
81                Path(dest_lib_path / "stm32wb" / "hci" / file_name).parent.mkdir(
82                    parents=True
83                )
84            shutil.copy(file_path, Path(dest_lib_path / "stm32wb" / "hci" / file_name))
85        else:
86            logging.error(f"File : {file_path} not found")
87            logging.error("Abort")
88            sys.exit()
89
90
91def update_ble_lib_readme(lib_path, make_version, make_commit):
92    """Update README file
93
94    Args:
95        dest_lib_path: library path
96        make_version: latest STM32Cube version.
97        make_commit: Commit corresponding to latest STM32Cube version.
98    """
99
100    readme_path = Path(lib_path / "stm32wb" / "hci" / "README")
101
102    with readme_path.open(mode="r") as readme_prev:
103        lines = (x for x in readme_prev.read().splitlines())
104
105    readme_path.unlink()
106
107    # Write README from previous one if exists
108    with open(str(readme_path), "w") as readme_file:
109        for LineItem in lines:
110            # change version nb
111            if "status" in LineItem.lower():
112                readme_file.write("Status:\n")
113                readme_file.write(f"   version {make_version}\n")
114                next(lines)  # skip next line
115            elif "commit" in LineItem.lower():
116                readme_file.write("Commit:\n")
117                readme_file.write(f"   {make_commit}")
118                next(lines)  # skip next line
119            # change patch list with a link to the release_note.html
120            elif "Patch List" in LineItem:
121                readme_file.write("Patch List:\n")
122                readme_file.write(
123                    "--> please check that the following list "
124                    + "is still valid:\n"
125                )
126            else:
127                readme_file.write(f"{LineItem}\n")
128
129        readme_file.flush()
130
131
132def build_patch_from_current_zephyr_version(
133    src_repo_path, temp_source_path, zephyr_lib_path, version
134):
135    """ Rebuild zephyr patch compare to cube files (current zephyr version) """
136
137    temp_source_lib_path = Path(temp_source_path / "lib")
138
139    # reset the STM32Cube repo to this current version
140    os_cmd(
141        ("git", "reset", "--hard", version),
142        cwd=src_repo_path,
143    )
144
145    # create Cube reference from zephyr version
146    shutil.rmtree(temp_source_path, onerror=common_utils.remove_readonly)
147    temp_source_lib_path.mkdir(parents=True)
148
149    copy_hci_files(
150        src_repo_path,
151        temp_source_lib_path,
152    )
153    os_cmd(("git", "init"), cwd=temp_source_path)
154    os_cmd(
155        ("git", "commit", "--allow-empty", "-m", "'Trigger notification'"),
156        cwd=temp_source_path,
157    )
158    os_cmd(
159        ("git", "add", "-A", Path(temp_source_lib_path / "*")),
160        cwd=temp_source_path,
161    )
162    os_cmd(
163        ("git", "commit", "-am", "ble lib from zephyr version"),
164        cwd=temp_source_path,
165    )
166
167    # Remove trailing whitespaces
168    os_cmd(
169        ("git", "rebase", "--whitespace=fix", "HEAD~1"),
170        cwd=temp_source_path,
171    )
172
173    # copy zephyr files
174    shutil.rmtree(temp_source_lib_path, onerror=common_utils.remove_readonly)
175    shutil.copytree(zephyr_lib_path, temp_source_lib_path)
176
177    # remove all files at root dir (like readme and cmakelist)
178    # so that it is not part of the patch
179    for file in temp_source_lib_path.glob("*"):
180        if file.is_file():
181            file.unlink()
182    Path(temp_source_lib_path / "stm32wb" / "hci" / "README").unlink()
183
184    # commit this current zephyr library file
185    os_cmd(("git", "add", "*"), cwd=temp_source_path)
186    os_cmd(("git", "commit", "-am", '"module"'), cwd=temp_source_path)
187
188    # Remove trailing space
189    os_cmd(
190        ("git", "rebase", "--whitespace=fix", "HEAD~1"),
191        cwd=temp_source_path,
192    )
193
194    # For unclear reason, using tuple ("git", "diff", ...) is failing on Linux
195    # especially for this command. Keep a single string.
196    os_cmd(
197        (
198            "git diff --ignore-space-at-eol HEAD~1 --output="
199            + str(zephyr_lib_path)
200            + "/ble_zephyr.patch"
201        ),
202        shell=True,
203        cwd=temp_source_path,
204    )
205    os_cmd(("dos2unix", "ble_zephyr.patch"), cwd=zephyr_lib_path)
206
207
208def update(
209    src_repo_path,
210    dest_lib_path,
211    temp_source_path,
212    current_version,
213    update_version,
214    commit,
215):
216    """Update ble library"""
217    logging.info(" ... Updating ble library ...")
218    build_patch_from_current_zephyr_version(
219        src_repo_path, temp_source_path, dest_lib_path, current_version
220    )
221    # reset the STM32Cube repo to this update version
222    os_cmd(
223        ("git", "reset", "--hard", update_version),
224        cwd=src_repo_path,
225    )
226    copy_hci_files(src_repo_path, dest_lib_path)
227    common_utils.apply_patch(dest_lib_path / "ble_zephyr.patch", dest_lib_path)
228    update_ble_lib_readme(dest_lib_path, update_version, commit)
229
230
231if __name__ == "__main__":
232    print("This script is not intend to be called directly\n")
233    print("It is used through serie_update.py\n")
234    sys.exit()
235