1#!/usr/bin/python
2"""
3SPDX-License-Identifier: Apache-2.0
4Copyright (c) 2024 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
16file_list_wb = [
17    "Middlewares/ST/STM32_WPAN/ble/core/ble_bufsize.h",
18    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/hw.h",
19    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.c",
20    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/shci/shci.h",
21    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/hci_tl.h",
22    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/mbox_def.h",
23    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl_if.c",
24    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl.c",
25    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/shci_tl.h",
26    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl.h",
27    "Middlewares/ST/STM32_WPAN/interface/patterns/ble_thread/tl/tl_mbox.c",
28    "Middlewares/ST/STM32_WPAN/stm32_wpan_common.h",
29    "Middlewares/ST/STM32_WPAN/utilities/dbg_trace.h",
30    "Middlewares/ST/STM32_WPAN/utilities/stm_list.c",
31    "Middlewares/ST/STM32_WPAN/utilities/stm_list.h",
32    "Middlewares/ST/STM32_WPAN/utilities/utilities_common.h",
33    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/Core/Inc/app_common.h",
34    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/Core/Inc/app_conf.h",
35    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/Core/Inc/hw_if.h",
36    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/STM32_WPAN/Target/"
37    + "hw_ipcc.c",
38    "Projects/P-NUCLEO-WB55.Nucleo/Applications/BLE/BLE_Hid/STM32_WPAN/App/"
39    + "tl_dbg_conf.h",
40]
41
42ble_heartrate_app_path = "Projects/NUCLEO-WBA55CG/Applications/BLE/BLE_HeartRate"
43
44file_list_wba = {
45    "auto": ["Middlewares/ST/STM32_WPAN/ble/stack/include/auto/ble_types.h",
46             ],
47    "reg_files": ["Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/_40nm_reg_files/"
48                  + "DWC_ble154combo.h",
49                  ],
50    "ll": ["Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/bsp.h",
51           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/common_types.h",
52           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/event_manager.h",
53           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/evnt_schdlr_gnrc_if.h",
54           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/hci.h",
55           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/ll_intf.h",
56           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/mem_intf.h",
57           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/os_wrapper.h",
58           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/power_table.h",
59           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/inc/pta.h",
60           "Middlewares/ST/STM32_WPAN/link_layer/ll_cmd_lib/config/ble_full/"
61           + "ll_fw_config.h",
62           ],
63    "hci": ["Middlewares/ST/STM32_WPAN/ble/stack/include/ble_bufsize.h",
64            "Middlewares/ST/STM32_WPAN/ble/stack/include/ble_const.h",
65            "Middlewares/ST/STM32_WPAN/ble/stack/include/ble_defs.h",
66            "Middlewares/ST/STM32_WPAN/ble/stack/include/ble_std.h",
67            "Middlewares/ST/STM32_WPAN/ble/stack/include/bleplat.h",
68            "Middlewares/ST/STM32_WPAN/ble/stack/include/blestack.h",
69            "Middlewares/ST/STM32_WPAN/link_layer/ll_sys/inc/linklayer_plat.h",
70            "Middlewares/ST/STM32_WPAN/link_layer/ll_sys/inc/ll_sys.h",
71            "Middlewares/ST/STM32_WPAN/link_layer/ll_sys/src/ll_sys_cs.c",
72            "Middlewares/ST/STM32_WPAN/link_layer/ll_sys/src/ll_sys_dp_slp.c",
73            "Middlewares/ST/STM32_WPAN/link_layer/ll_sys/src/ll_sys_intf.c",
74            "Middlewares/ST/STM32_WPAN/link_layer/ll_sys/src/ll_sys_startup.c",
75            "Middlewares/ST/STM32_WPAN/link_layer/ll_sys/inc/ll_sys_startup.h",
76            "Middlewares/ST/STM32_WPAN/stm32_wpan_common.h",
77            ble_heartrate_app_path + "/Core/Inc/app_common.h",
78            ble_heartrate_app_path + "/Core/Inc/app_conf.h",
79            ble_heartrate_app_path + "/Core/Inc/app_entry.h",
80            ble_heartrate_app_path + "/Core/Inc/utilities_conf.h",
81            ble_heartrate_app_path + "/Core/Inc/main.h",
82            ble_heartrate_app_path + "/System/Modules/Flash/rf_timing_synchro.c",
83            ble_heartrate_app_path + "/System/Modules/Flash/rf_timing_synchro.h",
84            ble_heartrate_app_path + "/System/Modules/Flash/flash_driver.c",
85            ble_heartrate_app_path + "/System/Modules/Flash/flash_driver.h",
86            ble_heartrate_app_path + "/System/Modules/Flash/flash_manager.c",
87            ble_heartrate_app_path + "/System/Modules/Flash/flash_manager.h",
88            ble_heartrate_app_path + "/System/Modules/RTDebug/debug_signals.h",
89            ble_heartrate_app_path + "/System/Modules/RTDebug/RTDebug.c",
90            ble_heartrate_app_path + "/System/Modules/RTDebug/RTDebug.h",
91            ble_heartrate_app_path + "/System/Modules/RTDebug/local_debug_tables.h",
92            ble_heartrate_app_path + "/System/Modules/scm.c",
93            ble_heartrate_app_path + "/System/Modules/scm.h",
94            ble_heartrate_app_path + "/System/Modules/stm_list.c",
95            ble_heartrate_app_path + "/System/Modules/stm_list.h",
96            ble_heartrate_app_path + "/System/Modules/utilities_common.h",
97            ble_heartrate_app_path + "/System/Interfaces/hw.h",
98            ble_heartrate_app_path + "/System/Interfaces/hw_aes.c",
99            ble_heartrate_app_path + "/System/Interfaces/hw_if.h",
100            ble_heartrate_app_path + "/System/Interfaces/hw_pka.c",
101            ble_heartrate_app_path + "/System/Interfaces/pka_p256.c",
102            ble_heartrate_app_path + "/System/Config/Log/log_module.c",
103            ble_heartrate_app_path + "/System/Config/Log/log_module.h",
104            ble_heartrate_app_path + "/System/Config/Debug_GPIO/app_debug.h",
105            ble_heartrate_app_path + "/System/Config/Debug_GPIO/debug_config.h",
106            ble_heartrate_app_path + "/STM32_WPAN/Target/power_table.c",
107            ble_heartrate_app_path + "/STM32_WPAN/Target/bpka.c",
108            ble_heartrate_app_path + "/STM32_WPAN/Target/bpka.h",
109            "Utilities/trace/adv_trace/stm32_adv_trace.h",
110            "Utilities/misc/stm32_mem.h",
111            "Utilities/tim_serv/stm32_timer.h",
112            "Utilities/misc/stm32_tiny_vsnprintf.h",
113            ],
114}
115
116
117def os_cmd(cmd, cwd=None, shell=False):
118    """Execute a command with subprocess.check_call()
119    Args:
120        cmd: string command to execute.
121        cwd: directory where to run command
122        shell: boolean to enable command interpretation by the shell
123
124    Returns:
125        return the returncode of the command after execution.
126    """
127    logging.debug("%s", f"{str(cmd)}      cwd:{str(cwd)}")
128
129    return subprocess.check_call(
130        cmd,
131        shell=shell,
132        cwd=cwd,
133        stdout=subprocess.DEVNULL,
134        stderr=subprocess.DEVNULL,
135    )
136
137
138def copy_hci_files(src_repo_path, dest_lib_path, stm32_serie):
139    """Copy sources files from Cube Firmware to zephyr"""
140    # remove existing *.c and *.h files
141    hci_path = Path(dest_lib_path / "hci")
142    if hci_path.exists():
143        for item in os.listdir(hci_path):
144            if item.endswith(".c") or item.endswith(".h"):
145                os.remove(hci_path / item)
146
147    if stm32_serie == "stm32wb":
148        if not hci_path.exists():
149            hci_path.mkdir(parents=True)
150
151        for file in file_list_wb:
152            file_path = Path(src_repo_path / file)
153            file_name = file_path.name
154            if file_path.exists():
155                # copy each file to destination
156                shutil.copy(file_path, Path(hci_path / file_name))
157            else:
158                logging.error(f"File : {file_path} not found")
159                logging.error("Abort")
160                sys.exit()
161
162    elif stm32_serie == "stm32wba":
163        # remove existing *.c and *.h files
164        auto_path = Path(hci_path / "auto")
165        ll_path = Path(hci_path / "ll")
166        reg_files_path = Path(ll_path / "_40nm_reg_files")
167        dir_paths = {"hci": hci_path, "auto": auto_path, "ll": ll_path,
168                     "reg_files": reg_files_path}
169
170        for dir_path in [auto_path, ll_path, reg_files_path]:
171            if dir_path.exists():
172                for item in os.listdir(dir_path):
173                    if item.endswith(".c") or item.endswith(".h"):
174                        os.remove(dir_path / item)
175
176        for dir_name in file_list_wba:
177            if not dir_paths[dir_name].exists():
178                dir_paths[dir_name].mkdir(parents=True)
179
180            for file in file_list_wba[dir_name]:
181                file_path = Path(src_repo_path / file)
182                file_name = file_path.name
183                if file_path.exists():
184                    # copy each file to destination
185                    shutil.copy(file_path, Path(dir_paths[dir_name]))
186                else:
187                    logging.error(f"File : {file_path} not found")
188                    logging.error("Abort")
189                    sys.exit()
190
191
192def update_ble_lib_readme(lib_path, make_version, make_commit):
193    """Update README file
194
195    Args:
196        dest_lib_path: library path
197        make_version: latest STM32Cube version.
198        make_commit: Commit corresponding to latest STM32Cube version.
199    """
200
201    readme_path = Path(lib_path / "hci" / "README")
202
203    with readme_path.open(mode="r") as readme_prev:
204        lines = (x for x in readme_prev.read().splitlines())
205
206    readme_path.unlink()
207
208    # Write README from previous one if exists
209    with open(str(readme_path), "w") as readme_file:
210        for line_item in lines:
211            # change version nb
212            if "status" in line_item.lower():
213                readme_file.write("Status:\n")
214                readme_file.write(f"   version {make_version}\n")
215                next(lines)  # skip next line
216            elif "commit" in line_item.lower():
217                readme_file.write("Commit:\n")
218                readme_file.write(f"   {make_commit}")
219                next(lines)  # skip next line
220            # change patch list with a link to the release_note.html
221            elif "Patch List" in line_item:
222                readme_file.write("Patch List:\n")
223                readme_file.write(
224                    "--> please check that the following list "
225                    + "is still valid:\n"
226                )
227            else:
228                readme_file.write(f"{line_item}\n")
229
230        readme_file.flush()
231
232
233def build_patch_from_current_zephyr_version(
234    src_repo_path, temp_source_path, zephyr_lib_path, version, stm32_serie
235):
236    """ Rebuild zephyr patch compare to cube files (current zephyr version) """
237
238    temp_source_lib_path = Path(temp_source_path / "lib" / stm32_serie)
239
240    # Checkout the current Zephyr version of the STM32Cube repo
241    os_cmd(
242        ("git", "checkout", "-f", "--recurse-submodules", version),
243        cwd=src_repo_path,
244    )
245
246    # create Cube reference from zephyr version
247    shutil.rmtree(temp_source_path, onerror=common_utils.remove_readonly)
248    temp_source_lib_path.mkdir(parents=True)
249
250    copy_hci_files(
251        src_repo_path,
252        temp_source_lib_path,
253        stm32_serie,
254    )
255    os_cmd(("git", "init"), cwd=temp_source_path)
256    os_cmd(
257        ("git", "commit", "--allow-empty", "-m", "'Trigger notification'"),
258        cwd=temp_source_path,
259    )
260    os_cmd(
261        ("git", "add", "-A", Path(temp_source_lib_path / "*")),
262        cwd=temp_source_path,
263    )
264    os_cmd(
265        ("git", "commit", "-am", "ble lib from zephyr version"),
266        cwd=temp_source_path,
267    )
268
269    # Remove trailing whitespaces
270    os_cmd(
271        ("git", "rebase", "--whitespace=fix", "HEAD~1"),
272        cwd=temp_source_path,
273    )
274
275    # copy zephyr files
276    shutil.rmtree(temp_source_lib_path, onerror=common_utils.remove_readonly)
277    shutil.copytree(zephyr_lib_path, temp_source_lib_path)
278
279    # remove all files at root dir (like readme and cmakelist)
280    # so that it is not part of the patch
281    for file in temp_source_lib_path.glob("*"):
282        if file.is_file():
283            file.unlink()
284    if Path(temp_source_lib_path / "hci" / "README").exists():
285        Path(temp_source_lib_path / "hci" / "README").unlink()
286
287    # commit this current zephyr library file
288    os_cmd(("git", "add", "*"), cwd=temp_source_path)
289    os_cmd(("git", "commit", "-am", '"module"'), cwd=temp_source_path)
290
291    # Remove trailing space
292    os_cmd(
293        ("git", "rebase", "--whitespace=fix", "HEAD~1"),
294        cwd=temp_source_path,
295    )
296
297    # For unclear reason, using tuple ("git", "diff", ...) is failing on Linux
298    # especially for this command. Keep a single string.
299    os_cmd(
300        (
301            "git diff --ignore-space-at-eol HEAD~1 --output="
302            + str(zephyr_lib_path)
303            + "/ble_zephyr.patch"
304        ),
305        shell=True,
306        cwd=temp_source_path,
307    )
308    os_cmd(("dos2unix", "ble_zephyr.patch"), cwd=zephyr_lib_path)
309
310
311def update(
312    src_repo_path,
313    dest_lib_path,
314    temp_source_path,
315    current_version,
316    update_version,
317    commit,
318    stm32_serie
319):
320    """Update ble library"""
321    logging.info(" ... Updating ble library ...")
322    if not dest_lib_path.exists():
323        dest_lib_path.mkdir(parents=True)
324
325    build_patch_from_current_zephyr_version(
326        src_repo_path, temp_source_path, dest_lib_path, current_version,
327        stm32_serie
328    )
329    # Checkout the latest version of the STM32Cube repo
330    os_cmd(
331        ("git", "checkout", "-f", "--recurse-submodules", update_version),
332        cwd=src_repo_path,
333    )
334    copy_hci_files(src_repo_path, dest_lib_path, stm32_serie)
335    common_utils.apply_patch(dest_lib_path / "ble_zephyr.patch", dest_lib_path)
336    if Path(dest_lib_path / "hci" / "README").exists():
337        update_ble_lib_readme(
338            dest_lib_path, update_version, commit)
339
340
341if __name__ == "__main__":
342    print("This script is not intend to be called directly\n")
343    print("It is used through serie_update.py\n")
344    sys.exit()
345