Pynrfjprog create dummy thread, how to avoid/delete them ?

Hi,

I'm devlopping python (v3.9.6) software to flash nRF52832 using pynrfjprog (v10.17.3) package.

The soft is a loop trying to erase and flash. But while debugging with VSCode, I see that pynrfjprog package  create "Dummy-X" threads and never release/kill them.

The point is, if the software run for a long time, more than 2000 thread can be running at the same time and take lot of ressources on the computer.

My question is, is there a way to erase/flash without creating this Dummy thread ? Or is there a way to delete them once the erase/flash action is over ?

Thanks in advance,

Antoine

Parents
  • Hello

    What software are you using to flash exactly? Is it a script you wrote yourself?

    If so, please share your script.

    Best regards,

    Einar

  • Hi Einar,

    It is in fact my own code. Please find bellow the script I'm using:

    import logging
    import pynrfjprog.HighLevel
    import threading
    
    class nRF528XXFlasher():
        api = None
        flashers = {}
        semaphore = threading.BoundedSemaphore(value=1)
    
        def __init__(self, snr=None, config={}, logger=None):
            self.config = config
    
            if logger is None:
                self.logger = logging.getLogger(__name__)
            else:
                self.logger = logger.getChild(__name__)
    
            self.logger.setLevel(self.config.get("log_level", "INFO"))
    
            try:
                nRF528XXFlasher.semaphore.acquire(timeout=3)
    
                if nRF528XXFlasher.api is None:
                    nRF528XXFlasher.api = pynrfjprog.HighLevel.API(self.config.get("nRF528XX_flasher_enable_log", False))
    
                if not nRF528XXFlasher.api.is_open():
                    nRF528XXFlasher.api.open()
    
                if snr is None:
                    probes_snrs = nRF528XXFlasher.api.get_connected_probes()
                    if len(probes_snrs) > 0:
                        self.logger.debug(f"nRF528XXFlasher possible serials : {probes_snrs}")
                        for probe_snr in probes_snrs:
                            logger.debug(probe_snr)
                            if probe_snr not in nRF528XXFlasher.flashers:
                                snr = probe_snr
                                break
            finally:
                nRF528XXFlasher.semaphore.release()
    
            self.snr = snr
            if self.snr is None:
                raise Exception(f"nRF528XX Flasher probe not found ({self.snr})")
    
            nRF528XXFlasher.flashers[snr] = self
    
            # Catch and redirect logs from the probe
            class ProbeLogFilter(logging.Filter):
                def __init__(self, flasher, name=""):
                    super().__init__(name)
                    self.flasher = flasher
    
                def filter(self, record):
                    if self.flasher.config.get("nRF528XX_flasher_enable_log", False):
                        if str(self.flasher.snr) in record.name:
                            self.flasher.logger.handle(record)
                    return False
    
            logging.getLogger(f"pynrfjprog.HighLevel.Probes.{self.snr}").addFilter(
                ProbeLogFilter(flasher=self))
    
        def __del__(self):
            for snr in nRF528XXFlasher.flashers:
                if nRF528XXFlasher.flashers[snr] == self:
                    nRF528XXFlasher.flashers.pop(snr)
                    break
            if len(nRF528XXFlasher.flashers) <= 0:
                if nRF528XXFlasher.api.is_open():
                    nRF528XXFlasher.api.close()
    
        def erase_app(self):
            with pynrfjprog.HighLevel.DebugProbe(nRF528XXFlasher.api, self.snr, log=self.config.get("nRF528XX_flasher_enable_log", True)) as probe:
                probe.erase(erase_action=pynrfjprog.HighLevel.EraseAction.ERASE_ALL)
            return True
    
        def flash_app(self, hex_file):
            with pynrfjprog.HighLevel.DebugProbe(nRF528XXFlasher.api, self.snr, pynrfjprog.HighLevel.CoProcessor.CP_APPLICATION, log=self.config.get("nRF528XX_flasher_enable_log", True)) as probe:
                probe.program(hex_file, program_options=pynrfjprog.HighLevel.ProgramOptions(verify=pynrfjprog.HighLevel.VerifyAction.VERIFY_READ, erase_action=pynrfjprog.HighLevel.EraseAction.ERASE_ALL, reset=pynrfjprog.HighLevel.ResetAction.RESET_SYSTEM))
            return True


    Best regards,

    Antoine

  • You can try to use LowLevel instead:

    (you might have to set up your logfilter again)

    import logging
    from pynrfjprog import LowLevel
    import threading
    
    class nRF528XXFlasher:
        flashers = dict()
        semaphore = threading.BoundedSemaphore(value=1)
        
        def __init__(self, snr=None, config={}, logger=None):
            self.config = config
            
            if logger is None:
                self.logger = logging.getLogger(__name__)
            else:
                self.logger = logger.getChild(__name__)
            self.logger.setLevel(self.config.get("log_level", "INFO"))
            
            try:
                nRF528XXFlasher.semaphore.acquire(timeout=3)
                if snr is None:
                    snr = self._get_random_snr()
                self.snr = snr
                nRF528XXFlasher.flashers[snr] = self
            finally:
                nRF528XXFlasher.semaphore.release()
                
            # Catch and redirect logs from the probe
            class ProbeLogFilter(logging.Filter):
                def __init__(self, flasher, name=""):
                    super().__init__(name)
                    self.flasher = flasher
                    
                def filter(self, record):
                    if self.flasher.config.get("nRF528XX_flasher_enable_log", False):
                        if str(self.flasher.snr) in record.name:
                            self.flasher.logger.handle(record)
                    return False
                    
            logging.getLogger(f"HighLevel.Probes.{self.snr}").addFilter(ProbeLogFilter(flasher=self))
            
        def _get_random_snr(self):
            with LowLevel.API(LowLevel.DeviceFamily.UNKNOWN) as api:
                probes_snrs = set(api.enum_emu_snr())
                self.logger.debug(f"nRF528XXFlasher possible serials : {probes_snrs}")
                available_snrs = probes_snrs.difference(nRF528XXFlasher.flashers.keys())
                if not available_snrs:
                    raise AssertionError("No available snrs")
                return available_snrs.pop()
                
        def __del__(self):
            for snr in nRF528XXFlasher.flashers:
                if nRF528XXFlasher.flashers[snr] == self:
                    nRF528XXFlasher.flashers.pop(snr)
                    break
                    
        def erase_app(self):
            with LowLevel.API(LowLevel.DeviceFamily.NRF52, log=self.config.get("nRF528XX_flasher_enable_log")) as api:
                api.connect_to_emu_with_snr(self.snr)
                api.erase_all()
            return True
            
        def flash_app(self, hex_file):
            with LowLevel.API(LowLevel.DeviceFamily.NRF52, log=self.config.get("nRF528XX_flasher_enable_log")) as api:
                api.connect_to_emu_with_snr(self.snr)
                api.program_file(hex_file)
                api.verify_file(hex_file)
                api.sys_reset()
            return True

    -Einar

Reply
  • You can try to use LowLevel instead:

    (you might have to set up your logfilter again)

    import logging
    from pynrfjprog import LowLevel
    import threading
    
    class nRF528XXFlasher:
        flashers = dict()
        semaphore = threading.BoundedSemaphore(value=1)
        
        def __init__(self, snr=None, config={}, logger=None):
            self.config = config
            
            if logger is None:
                self.logger = logging.getLogger(__name__)
            else:
                self.logger = logger.getChild(__name__)
            self.logger.setLevel(self.config.get("log_level", "INFO"))
            
            try:
                nRF528XXFlasher.semaphore.acquire(timeout=3)
                if snr is None:
                    snr = self._get_random_snr()
                self.snr = snr
                nRF528XXFlasher.flashers[snr] = self
            finally:
                nRF528XXFlasher.semaphore.release()
                
            # Catch and redirect logs from the probe
            class ProbeLogFilter(logging.Filter):
                def __init__(self, flasher, name=""):
                    super().__init__(name)
                    self.flasher = flasher
                    
                def filter(self, record):
                    if self.flasher.config.get("nRF528XX_flasher_enable_log", False):
                        if str(self.flasher.snr) in record.name:
                            self.flasher.logger.handle(record)
                    return False
                    
            logging.getLogger(f"HighLevel.Probes.{self.snr}").addFilter(ProbeLogFilter(flasher=self))
            
        def _get_random_snr(self):
            with LowLevel.API(LowLevel.DeviceFamily.UNKNOWN) as api:
                probes_snrs = set(api.enum_emu_snr())
                self.logger.debug(f"nRF528XXFlasher possible serials : {probes_snrs}")
                available_snrs = probes_snrs.difference(nRF528XXFlasher.flashers.keys())
                if not available_snrs:
                    raise AssertionError("No available snrs")
                return available_snrs.pop()
                
        def __del__(self):
            for snr in nRF528XXFlasher.flashers:
                if nRF528XXFlasher.flashers[snr] == self:
                    nRF528XXFlasher.flashers.pop(snr)
                    break
                    
        def erase_app(self):
            with LowLevel.API(LowLevel.DeviceFamily.NRF52, log=self.config.get("nRF528XX_flasher_enable_log")) as api:
                api.connect_to_emu_with_snr(self.snr)
                api.erase_all()
            return True
            
        def flash_app(self, hex_file):
            with LowLevel.API(LowLevel.DeviceFamily.NRF52, log=self.config.get("nRF528XX_flasher_enable_log")) as api:
                api.connect_to_emu_with_snr(self.snr)
                api.program_file(hex_file)
                api.verify_file(hex_file)
                api.sys_reset()
            return True

    -Einar

Children
Related