[Bouffalolab] Update bflb-iot-tool version and flash script (#29379)

* [Bouffalolab] Update flash tool to 1.8.6 and readme

* fix spell

* fix lintcode and testdata

* fix lintcode

* fix restyle
diff --git a/examples/lighting-app/bouffalolab/README.md b/examples/lighting-app/bouffalolab/README.md
index a7f7867..c3938d8 100644
--- a/examples/lighting-app/bouffalolab/README.md
+++ b/examples/lighting-app/bouffalolab/README.md
@@ -11,10 +11,11 @@
 -   `BL602-NIGHT-LIGHT`
 -   `XT-ZB6-DevKit`
 -   `BL706-NIGHT-LIGHT`
--   `BL704L-DVK`
+-   `BL706DK`
+-   `BL704LDK`
 
-> Warning: Changing the PID may cause compilation problems, we recommend leaving
-> it as the default while using this example.
+> Warning: Changing the VID/PID may cause compilation problems, we recommend
+> leaving it as the default while using this example.
 
 ## BL602
 
@@ -24,10 +25,17 @@
 
 <img src="../../platform/bouffalolab/doc/chart/BL602-IoT-Matter_V1.png" style="zoom:25%;" />
 
-## BL706
+## BL70x
 
-BL702/BL706 is combo chip-set for BLE and IEEE 802.15.4/ZigBee/Thread. In some
-cases, e.g. in SDK, we use BL702 as a general name for BL702/BL706 family.
+BL70x is combo chip-set for BLE and IEEE 802.15.4/ZigBee/Thread.
+
+-   BL702/BL706 has 14dbm tx power and is recommended for routing devices. SDK
+    uses BL702 as a general name.
+-   BL702L/BL704L is designed for low power application. SDK uses BL702L as a
+    general name.
+
+BL70x has fully certified with all Thread 1.3 features, included Thread `SSED`
+and Thread Border Router with `DUA manager`.
 
 ### `XT-ZB6-DevKit`
 
@@ -47,12 +55,12 @@
     git clone https://github.com/project-chip/connectedhomeip.git
     cd connectedhomeip
     git submodule update --init --recursive
-    source ./scripts/activate.sh
+    source ./scripts/activate.sh -p bouffalolab
     ```
 
-    > After environment setup Bouffalolab flash tool, `bflb-iot-tool`, imports
-    > under this environment. If not, please try `scripts/bootstrap.sh` for
-    > matter environment update.
+    > After environment setup `Bouffalo Lab` flash tool, `bflb-iot-tool`,
+    > imports under this environment. If not, please try
+    > `scripts/bootstrap.sh -p bouffalolab` for matter environment update.
 
 -   Setup build environment for `Bouffalo Lab` SoC
 
@@ -72,15 +80,17 @@
 
 ## Build CHIP Lighting App example
 
-The following steps take examples for BL602 develop board `BL602-IoT-Matter-V1`,
-BL706 develop board `XT-ZB6-DevKit` and BL704L DVK board `BL704L-DVK`
+The following steps take examples for `BL602-IoT-Matter-V1` bl602 board, BL706
+develop `XT-ZB6-DevKit` and `BL706DK` bl706 board, and `BL704LDK` BL704L board .
 
 -   Build lighting app with UART baudrate 2000000
 
     ```
     ./scripts/build/build_examples.py --target bouffalolab-bl602-iot-matter-v1-light build
     ./scripts/build/build_examples.py --target bouffalolab-xt-zb6-devkit-light build
-    ./scripts/build/build_examples.py --target bouffalolab-bl704l-dvk-light build
+    ./scripts/build/build_examples.py --target bouffalolab-bl704ldk-light build
+    ./scripts/build/build_examples.py --target bouffalolab-bl706dk-light-ethernet build
+    ./scripts/build/build_examples.py --target bouffalolab-bl706dk-light-wifi build
     ```
 
 -   Build lighting app with UART baudrate 115200
@@ -97,14 +107,39 @@
     ./scripts/build/build_examples.py --target bouffalolab-xt-zb6-devkit-light-rpc build
     ```
 
+### Build options with build_examples.py
+
+-   `-shell`, enable UART command line
+-   `-115200`, set UART baudrate to 115200 for log and command line
+-   `-rpc`, enable Pigweed RPC feature
+-   `-cdc`, enable USB CDC feature, only support for BL706, and can't work with
+    Ethernet Board
+-   `-resetCnt`, enable feature to do factory reset when continues power cycle
+    is greater than 3
+-   `-mfd`, enable Matter factory data feature, which load factory data from
+    `DTS` region and `MFD` partition
+    -   Please contact to `Bouffalo Lab` for Matter factory data support.
+-   `-mfdtest`, enable Matter factory data module, but only load factory data
+    from `FactoryDataProvider.cpp` file.
+-   `-wifi`, to specify that connectivity Wi-Fi is enabled for Matter
+    application.
+-   `-ethernet`, to specify that connectivity Ethernet is enabled for Matter
+    application.
+-   `-thread`, to specify that connectivity Thread is enabled for Matter
+    application.
+-   `-fp`, to specify to enable frame pointer feature to print call stack when
+    hit an exception for debug purpose.
+
 ## Download image
 
 -   Using script `*.flash.py`.
 
-    After building gets done, python script
-    `chip-bl602-lighting-example.flash.py` or
-    `chip-bl702-lighting-example.flash.py` will generate under build output
-    folder for BL602 or BL702 building.
+    After building gets done, python script `*.flash.py` will generate under
+    build output folder, such as
+
+    -   `chip-bl602-lighting-example.flash.py` for BL602
+    -   `chip-bl702-lighting-example.flash.py` for BL702
+    -   `chip-bl702l-lighting-example.flash.py` for BL702L
 
     > Note 1, `*.flash.py` should be ran under Matter build environment; if
     > python module `bflb_iot_tool` is not found, please try to do
@@ -126,12 +161,13 @@
     -   Type following command for image download. Please set serial port
         accordingly, here we use /dev/ttyACM0 as a serial port example.
 
-        -   `bl602-iot-matter-v1` and `bl704l-dvk` without additional build
-            options
+        -   `bl602-iot-matter-v1`, `xt-zb6-devkit` and `bl704ldk` without
+            additional build options
 
             ```shell
             ./out/bouffalolab-bl602-iot-matter-v1-light/chip-bl602-lighting-example.flash.py --port /dev/ttyACM0
-            ./out/bouffalolab-bl704l-dvk-light/chip-bl702l-lighting-example.flash.py --port /dev/ttyACM0
+            ./out/bouffalolab-xt-zb6-devkit-light/chip-bl702-lighting-example.flash.py --port /dev/ttyACM0
+            ./out/bouffalolab-bl704ldk-light/chip-bl702l-lighting-example.flash.py --port /dev/ttyACM0
             ```
 
         -   `xt-zb6-devkit` with 115200 baudrate setting
@@ -146,7 +182,7 @@
             ```shell
             ./out/bouffalolab-bl602-iot-matter-v1-light/chip-bl602-lighting-example.flash.py --port /dev/ttyACM0 --erase
             ./out/bouffalolab-xt-zb6-devkit-light-115200/chip-bl702-lighting-example.flash.py --port /dev/ttyACM0 --erase
-            ./out/bouffalolab-bl704l-dvk-light/chip-bl702l-lighting-example.flash.py --port /dev/ttyACM0 --erase
+            ./out/bouffalolab-bl704ldk-light/chip-bl702l-lighting-example.flash.py --port /dev/ttyACM0 --erase
             ```
 
             > Note, better to append --erase option to download image for BL602
diff --git a/scripts/build/build/targets.py b/scripts/build/build/targets.py
index 10a8da1..6d039d5 100755
--- a/scripts/build/build/targets.py
+++ b/scripts/build/build/targets.py
@@ -642,6 +642,7 @@
     target.AppendModifier('wifi', enable_wifi=True)
     target.AppendModifier('thread', enable_thread=True)
     target.AppendModifier('fp', enable_frame_ptr=True)
+    target.AppendModifier('memmonitor', enable_heap_monitoring=True)
 
     return target
 
diff --git a/scripts/build/builders/bouffalolab.py b/scripts/build/builders/bouffalolab.py
index 85bb48c..245161c 100644
--- a/scripts/build/builders/bouffalolab.py
+++ b/scripts/build/builders/bouffalolab.py
@@ -90,7 +90,8 @@
                  enable_ethernet: bool = False,
                  enable_wifi: bool = False,
                  enable_thread: bool = False,
-                 enable_frame_ptr: bool = False
+                 enable_frame_ptr: bool = False,
+                 enable_heap_monitoring: bool = False
                  ):
 
         if 'BL602' == module_type:
@@ -137,19 +138,16 @@
 
         # hardware connectivity support check
         if bouffalo_chip == "bl602":
-
             if enable_ethernet or enable_thread:
                 raise Exception('SoC %s doesn\'t support connectivity Ethernet/Thread.' % bouffalo_chip)
 
         elif bouffalo_chip == "bl702":
-
             self.argsOpt.append('module_type=\"{}\"'.format(module_type))
             if board != BouffalolabBoard.BL706DK:
                 if enable_ethernet or enable_wifi:
                     raise Exception('Board %s doesn\'t support connectivity Ethernet/Wi-Fi.' % board)
 
         elif bouffalo_chip == "bl702l":
-
             if enable_ethernet or enable_wifi:
                 raise Exception('SoC %s doesn\'t support connectivity Ethernet/Wi-Fi currently.' % bouffalo_chip)
 
@@ -203,6 +201,8 @@
         else:
             self.argsOpt.append("enable_debug_frame_ptr=false")
 
+        self.argsOpt.append("enable_heap_monitoring={}".format(str(enable_heap_monitoring).lower()))
+
         try:
             self.argsOpt.append('bouffalolab_sdk_root="%s"' % os.environ['BOUFFALOLAB_SDK_ROOT'])
         except KeyError as err:
@@ -261,4 +261,5 @@
         os.system("cp " + ota_images_image + " " + ota_images_dev_image)
 
         logging.info("PostBuild:")
-        logging.info("Bouffalo Lab OTA format image: " + self.app.AppNamePrefix(self.chip_name) + ".bin.xz.hash is generated.")
+        logging.info("Bouffalo Lab OTA format image without signature: " +
+                     self.app.AppNamePrefix(self.chip_name) + ".bin.xz.hash is generated.")
diff --git a/scripts/build/testdata/all_targets_linux_x64.txt b/scripts/build/testdata/all_targets_linux_x64.txt
index b501e2f..e7500ab 100644
--- a/scripts/build/testdata/all_targets_linux_x64.txt
+++ b/scripts/build/testdata/all_targets_linux_x64.txt
@@ -1,7 +1,7 @@
 ameba-amebad-{all-clusters,all-clusters-minimal,light,light-switch,pigweed}
 asr-{asr582x,asr595x,asr550x}-{all-clusters,all-clusters-minimal,lighting,light-switch,lock,bridge,temperature-measurement,thermostat,ota-requestor,dishwasher,refrigerator}[-ota][-shell][-no_logging][-factory][-rotating_id][-rio]
 android-{arm,arm64,x86,x64,androidstudio-arm,androidstudio-arm64,androidstudio-x86,androidstudio-x64}-{chip-tool,chip-test,tv-server,tv-casting-app,java-matter-controller,virtual-device-app}[-no-debug]
-bouffalolab-{bl602-iot-matter-v1,bl602-night-light,xt-zb6-devkit,bl706-night-light,bl706dk,bl704ldk}-light[-shell][-115200][-rpc][-cdc][-resetcnt][-rotating_device_id][-mfd][-mfdtest][-ethernet][-wifi][-thread][-fp]
+bouffalolab-{bl602-iot-matter-v1,bl602-night-light,xt-zb6-devkit,bl706-night-light,bl706dk,bl704ldk}-light[-shell][-115200][-rpc][-cdc][-resetcnt][-rotating_device_id][-mfd][-mfdtest][-ethernet][-wifi][-thread][-fp][-memmonitor]
 cc32xx-lock
 ti-cc13x2x7_26x2x7-{lighting,lock,pump,pump-controller}[-mtd]
 ti-cc13x4_26x4-{all-clusters,lighting,lock,pump,pump-controller}[-mtd][-ftd]
diff --git a/scripts/flashing/bouffalolab_firmware_utils.py b/scripts/flashing/bouffalolab_firmware_utils.py
index 03aabaa..402f045 100644
--- a/scripts/flashing/bouffalolab_firmware_utils.py
+++ b/scripts/flashing/bouffalolab_firmware_utils.py
@@ -13,15 +13,19 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+import importlib.metadata
+import logging
 import os
 import pathlib
 import re
+import shutil
 import sys
 
-import bflb_iot_tool
-import bflb_iot_tool.__main__
+import coloredlogs
 import firmware_utils
 
+coloredlogs.install(level='DEBUG')
+
 # Additional options that can be use to configure an `Flasher`
 # object (as dictionary keys) and/or passed as command line options.
 BOUFFALO_OPTIONS = {
@@ -72,7 +76,7 @@
             },
         },
         'build': {
-            'help': 'Build image',
+            'help': 'Build OTA image',
             'default': None,
             'argparse': {
                 'action': 'store_true'
@@ -87,7 +91,7 @@
             }
         },
         'pk': {
-            'help': 'public key to sign and encrypt firmware. Available for OTA image building.',
+            'help': 'public key to sign firmware to flash or sign ota image.',
             'default': None,
             'argparse': {
                 'metavar': 'path',
@@ -95,7 +99,7 @@
             }
         },
         'sk': {
-            'help': 'private key to sign and encrypt firmware. Available for OTA image building.',
+            'help': 'private key to sign firmware to flash or sign ota image.',
             'default': None,
             'argparse': {
                 'metavar': 'path',
@@ -127,7 +131,7 @@
 
         for root, dirs, files in os.walk(config_path, topdown=False):
             for name in files:
-                print("get_boot_image", root, boot2_image)
+                logging.info("get_boot_image {} {}".format(root, boot2_image))
                 if boot2_image:
                     return os.path.join(root, boot2_image)
                 else:
@@ -138,13 +142,16 @@
 
         return boot_image_guess
 
-    def get_dts_file(self, config_path, xtal_value):
+    def get_dts_file(self, config_path, xtal_value, chip_name):
 
         for root, dirs, files in os.walk(config_path, topdown=False):
             for name in files:
-                if name.find(xtal_value) >= 0:
-                    return os.path.join(config_path, name)
-
+                if chip_name == 'bl702':
+                    if name.find("bl_factory_params_IoTKitA_32M.dts") >= 0:
+                        return os.path.join(config_path, name)
+                else:
+                    if name.find(xtal_value) >= 0:
+                        return os.path.join(config_path, name)
         return None
 
     def verify(self):
@@ -159,14 +166,38 @@
         """Perform actions on the device according to self.option."""
         self.log(3, 'Options:', self.option)
 
+        try:
+            import bflb_iot_tool
+            import bflb_iot_tool.__main__
+
+            version_target_str = "1.8.6"
+            version_target = version_target_str.split('.')
+            version_target = "".join(["%03d" % int(var) for var in version_target])
+
+            version_current_str = importlib.metadata.version("bflb_iot_tool")
+            version_current = version_current_str.split('.')
+            version_current = "".join(["%03d" % int(var) for var in version_current])
+
+            if version_current < version_target:
+                raise Exception("bflb_iot_tool {} version is less than {}".format(version_current_str, version_target_str))
+
+        except Exception as e:
+
+            logging.error('Please try the following command to setup or upgrade Bouffalo Lab environment:')
+            logging.error('source scripts/activate.sh -p bouffalolab')
+            logging.error('Or')
+            logging.error('source scripts/bootstrap.sh -p bouffalolab')
+
+            logging.error('If upgrade bflb_iot_tool failed, try pip uninstall bflb_iot_tool first.')
+
+            raise Exception(e)
+
         tool_path = os.path.dirname(bflb_iot_tool.__file__)
 
         options_keys = BOUFFALO_OPTIONS["configuration"].keys()
         arguments = [__file__]
         work_dir = None
 
-        print("self.option", self.option)
-
         if self.option.reset:
             self.reset()
         if self.option.verify_application:
@@ -178,10 +209,11 @@
         dts_path = None
         xtal_value = None
 
-        is_for_ota_image_building = False
+        is_for_ota_image_building = None
         is_for_programming = False
         has_private_key = False
         has_public_key = False
+        ota_output_folder = None
 
         boot2_image = None
 
@@ -214,6 +246,8 @@
                 else:
                     arg = ("--{}={}".format(key, value)).strip()
 
+                arguments.append(arg)
+
             if key == "chipname":
                 chip_name = value
             elif key == "xtal":
@@ -232,24 +266,24 @@
             elif "sk" == key:
                 if value:
                     has_private_key = True
-
-            arguments.append(arg)
-
-            print(key, value)
+            elif "ota" == key and value:
+                ota_output_folder = os.path.join(os.getcwd(), value)
 
         if is_for_ota_image_building and is_for_programming:
-            print("ota imge build can't work with image programming")
-            return self
+            logging.error("ota imge build can't work with image programming")
+            raise Exception("Wrong operation.")
 
-        if is_for_ota_image_building:
-            if (has_private_key is not has_public_key) and (has_private_key or has_public_key):
-                print("For ota image signature, key pair must be used together")
-                return self
+        if not ((has_private_key and has_public_key) or (not has_public_key and not has_private_key)):
+            logging.error("Key pair expects a pair of public key and private.")
+            raise Exception("Wrong key pair.")
 
-        print(dts_path, xtal_value)
+        if is_for_ota_image_building == "ota_sign" and (not has_private_key or not has_public_key):
+            logging.error("Expecting key pair to sign OTA image.")
+            raise Exception("Wrong key pair.")
+
         if not dts_path and xtal_value:
             chip_config_path = os.path.join(tool_path, "chips", chip_name, "device_tree")
-            dts_path = self.get_dts_file(chip_config_path, xtal_value)
+            dts_path = self.get_dts_file(chip_config_path, xtal_value, chip_name)
             arguments.append("--dts")
             arguments.append(dts_path)
 
@@ -262,19 +296,30 @@
             if self.option.erase:
                 arguments.append("--erase")
 
-                if chip_name == "bl602":
-                    chip_config_path = os.path.join(tool_path, "chips", chip_name, "builtin_imgs")
-                    boot2_image = self.get_boot_image(chip_config_path, boot2_image)
-                    arguments.append("--boot2")
-                    arguments.append(boot2_image)
+            if chip_name in {"bl602", "bl702"}:
+                chip_config_path = os.path.join(tool_path, "chips", chip_name, "builtin_imgs")
+                boot2_image = self.get_boot_image(chip_config_path, boot2_image)
+                arguments.append("--boot2")
+                arguments.append(boot2_image)
 
         os.chdir(work_dir)
         arguments[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', arguments[0])
         sys.argv = arguments
 
-        print("arguments", arguments)
+        if ota_output_folder:
+            if os.path.exists(ota_output_folder):
+                shutil.rmtree(ota_output_folder)
+            os.mkdir(ota_output_folder)
+
+        logging.info("Arguments {}".format(arguments))
         bflb_iot_tool.__main__.run_main()
 
+        if ota_output_folder:
+            ota_images = os.listdir(ota_output_folder)
+            for img in ota_images:
+                if img not in ['FW_OTA.bin.xz.hash']:
+                    os.remove(os.path.join(ota_output_folder, img))
+
         return self
 
 
diff --git a/scripts/setup/requirements.bouffalolab.txt b/scripts/setup/requirements.bouffalolab.txt
index acd5fa7..a66a479 100644
--- a/scripts/setup/requirements.bouffalolab.txt
+++ b/scripts/setup/requirements.bouffalolab.txt
@@ -1,4 +1,4 @@
-bflb-iot-tool>=1.8.0
+bflb-iot-tool>=1.8.6
 jsonschema>=4.4.0
 cbor2>=5.4.3
 ecdsa>=0.18.0
diff --git a/src/platform/bouffalolab/BL702/ConnectivityManagerImpl.cpp b/src/platform/bouffalolab/BL702/ConnectivityManagerImpl.cpp
index 4969272..24df9f3 100644
--- a/src/platform/bouffalolab/BL702/ConnectivityManagerImpl.cpp
+++ b/src/platform/bouffalolab/BL702/ConnectivityManagerImpl.cpp
@@ -128,7 +128,6 @@
 
     if ((LWIP_NSC_IPV6_ADDR_STATE_CHANGED & reason) && args)
     {
-
         if (args->ipv6_addr_state_changed.addr_index >= LWIP_IPV6_NUM_ADDRESSES ||
             ip6_addr_islinklocal(netif_ip6_addr(nif, args->ipv6_addr_state_changed.addr_index)))
         {