add progress info

This commit is contained in:
Sergey Shchelkanov 2023-06-01 15:24:44 +03:00
parent 36d0e57272
commit ed6054f549
2 changed files with 87 additions and 62 deletions

View File

@ -19,7 +19,7 @@ PM_Clk_APB_P_Set_OFFSET = 0x1C
PM_CLOCK_CPU_S = 0 PM_CLOCK_CPU_S = 0
PM_CLOCK_CPU_M = (1 << PM_CLOCK_CPU_S) PM_CLOCK_CPU_M = (1 << PM_CLOCK_CPU_S)
PM_CLOCK_EEPROM_S = 1 PM_CLOCK_EEPROM_S = 1
PM_CLOCK_EEPROM_M = (1 << PM_CLOCK_EEPROM_S) PM_CLOCK_EEPROM_M = (1 << PM_CLOCK_EEPROM_S)
PM_CLOCK_RAM_S = 2 PM_CLOCK_RAM_S = 2
PM_CLOCK_RAM_M = (1 << PM_CLOCK_RAM_S) PM_CLOCK_RAM_M = (1 << PM_CLOCK_RAM_S)
PM_CLOCK_SPIFI_S = 3 PM_CLOCK_SPIFI_S = 3
@ -89,8 +89,9 @@ EEPROM_BEH_GLOB = 3
EEPROM_PAGE_MASK = 0x1F80 EEPROM_PAGE_MASK = 0x1F80
def eeprom_sysinit(openocd: OpenOcdTclRpc): def eeprom_sysinit(openocd: OpenOcdTclRpc):
print("MCU clock init...") print("MCU clock init...", flush=True)
openocd.write_word(WU_BASE_ADDRESS + WU_Clocks_OFFSET, 0x202) openocd.write_word(WU_BASE_ADDRESS + WU_Clocks_OFFSET, 0x202)
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_P_Set_OFFSET, 0xffffffff) openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_P_Set_OFFSET, 0xffffffff)
@ -99,7 +100,7 @@ def eeprom_sysinit(openocd: OpenOcdTclRpc):
def eeprom_global_erase(openocd: OpenOcdTclRpc): def eeprom_global_erase(openocd: OpenOcdTclRpc):
print("EEPROM global erase...") print("EEPROM global erase...", flush=True)
with OpenOcdTclRpc() as openocd: with OpenOcdTclRpc() as openocd:
openocd.write_word(EEPROM_REGS_NCYCRL, 1 << EEPROM_N_LD_S | openocd.write_word(EEPROM_REGS_NCYCRL, 1 << EEPROM_N_LD_S |
3 << EEPROM_N_R_1_S | 1 << EEPROM_N_R_2_S) 3 << EEPROM_N_R_1_S | 1 << EEPROM_N_R_2_S)
@ -118,9 +119,10 @@ def eeprom_global_erase(openocd: OpenOcdTclRpc):
(EEPROM_OP_ER << EEPROM_OP_S) | (EEPROM_BEH_GLOB << EEPROM_WRBEH_S) (EEPROM_OP_ER << EEPROM_OP_S) | (EEPROM_BEH_GLOB << EEPROM_WRBEH_S)
)) ))
def eeprom_global_erase_check(openocd: OpenOcdTclRpc): def eeprom_global_erase_check(openocd: OpenOcdTclRpc):
print("EEPROM global erase check through APB...") print("EEPROM global erase check through APB...", flush=True)
print(" Read Data at ...") print(" Read Data at ...", flush=True)
ex_value = 0x00000000 ex_value = 0x00000000
openocd.write_word(EEPROM_REGS_EEA, 0x00000000) openocd.write_word(EEPROM_REGS_EEA, 0x00000000)
for i in range(0, 64): for i in range(0, 64):
@ -128,19 +130,22 @@ def eeprom_global_erase_check(openocd: OpenOcdTclRpc):
for j in range(0, 32): for j in range(0, 32):
value = openocd.read_memory(EEPROM_REGS_EEDAT, 32, 1)[0] value = openocd.read_memory(EEPROM_REGS_EEDAT, 32, 1)[0]
if ex_value != value: if ex_value != value:
print(f"Unexpect value at Row {i}, Word {j}, expect {ex_value:#0x}, {value:#0x}") print(
f"Unexpect value at Row {i}, Word {j}, expect {ex_value:#0x}, {value:#0x}", flush=True)
def eeprom_write_word(openocd: OpenOcdTclRpc, address:int, word:int): def eeprom_write_word(openocd: OpenOcdTclRpc, address: int, word: int):
openocd.write_word(EEPROM_REGS_EECON, 1 << EEPROM_BWE_S) openocd.write_word(EEPROM_REGS_EECON, 1 << EEPROM_BWE_S)
openocd.write_word(EEPROM_REGS_EEA, address) openocd.write_word(EEPROM_REGS_EEA, address)
# buffer load # buffer load
openocd.write_word(EEPROM_REGS_EEDAT, word) openocd.write_word(EEPROM_REGS_EEDAT, word)
openocd.write_word(EEPROM_REGS_EECON, (1 << EEPROM_EX_S) | (1 << EEPROM_BWE_S) | (EEPROM_OP_PR << EEPROM_OP_S)) openocd.write_word(EEPROM_REGS_EECON, (1 << EEPROM_EX_S) | (
1 << EEPROM_BWE_S) | (EEPROM_OP_PR << EEPROM_OP_S))
time.sleep(0.001) time.sleep(0.001)
def eeprom_write_page(openocd: OpenOcdTclRpc, address:int, data:List[int]):
print(f"Writing page {address:#06x}...") def eeprom_write_page(openocd: OpenOcdTclRpc, address: int, data: List[int], progress: str = ""):
print(f"Writing page {address:#06x}... {progress}", flush=True)
openocd.write_word(EEPROM_REGS_EECON, 1 << EEPROM_BWE_S) openocd.write_word(EEPROM_REGS_EECON, 1 << EEPROM_BWE_S)
openocd.write_word(EEPROM_REGS_EEA, address) openocd.write_word(EEPROM_REGS_EEA, address)
page_address = address & EEPROM_PAGE_MASK page_address = address & EEPROM_PAGE_MASK
@ -148,23 +153,26 @@ def eeprom_write_page(openocd: OpenOcdTclRpc, address:int, data:List[int]):
# buffer load # buffer load
for word in data: for word in data:
if ((address + n) & EEPROM_PAGE_MASK) != page_address: if ((address + n) & EEPROM_PAGE_MASK) != page_address:
raise Exception("ERROR: word outside page!") raise Exception("ERROR: word outside page!", flush=True)
openocd.write_word(EEPROM_REGS_EEDAT, word) openocd.write_word(EEPROM_REGS_EEDAT, word)
openocd.write_word(EEPROM_REGS_EECON, (1 << EEPROM_EX_S) | (1 << EEPROM_BWE_S) | (EEPROM_OP_PR << EEPROM_OP_S)) openocd.write_word(EEPROM_REGS_EECON, (1 << EEPROM_EX_S) | (
1 << EEPROM_BWE_S) | (EEPROM_OP_PR << EEPROM_OP_S))
time.sleep(0.001) time.sleep(0.001)
def eeprom_check_data_apb(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int: def eeprom_check_data_apb(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int:
if print_progress: if print_progress:
print("EEPROM check through APB...") print("EEPROM check through APB...", flush=True)
openocd.write_word(EEPROM_REGS_EEA, offset) openocd.write_word(EEPROM_REGS_EEA, offset)
word_num = 0 word_num = 0
progress = 0 progress = 0
if print_progress: if print_progress:
print("[", end="", flush=True) print("[", end="", flush=True)
for word in words: for word in words:
value:int = openocd.read_word(EEPROM_REGS_EEDAT) value: int = openocd.read_word(EEPROM_REGS_EEDAT)
if words[word_num] != value: if words[word_num] != value:
print(f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}") print(
f"Unexpect value at {word_num} word, expect {word:#0x}, get {value:#0x}", flush=True)
return 1 return 1
word_num += 1 word_num += 1
curr_progress = int((word_num * 50) / len(words)) curr_progress = int((word_num * 50) / len(words))
@ -172,35 +180,37 @@ def eeprom_check_data_apb(openocd: OpenOcdTclRpc, words: List[int], offset: int,
print("#"*(curr_progress - progress), end="", flush=True) print("#"*(curr_progress - progress), end="", flush=True)
progress = curr_progress progress = curr_progress
if print_progress: if print_progress:
print("]") print("]", flush=True)
print("EEPROM check through APB done!") print("EEPROM check through APB done!", flush=True)
return 0 return 0
def eeprom_check_data_ahb_lite(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int: def eeprom_check_data_ahb_lite(openocd: OpenOcdTclRpc, words: List[int], offset: int, print_progress=True) -> int:
if print_progress: if print_progress:
print("EEPROM check through AHB-Lite...") print("EEPROM check through AHB-Lite...", flush=True)
mem_array = openocd.read_memory(0x01000000 + offset, 32, len(words)) mem_array = openocd.read_memory(0x01000000 + offset, 32, len(words))
if len(words) != len(mem_array): if len(words) != len(mem_array):
raise Exception("Wrong number of words in read_memory output!") raise Exception(
"Wrong number of words in read_memory output!", flush=True)
progress = 0 progress = 0
if print_progress: if print_progress:
print("[", end="", flush=True) print("[", end="", flush=True)
for word_num in range(len(words)): for word_num in range(len(words)):
if words[word_num] != mem_array[word_num]: if words[word_num] != mem_array[word_num]:
print(f"Unexpect value at {word_num} word, expect {words[word_num]:#0x}, \ print(f"Unexpect value at {word_num} word, expect {words[word_num]:#0x}, "
get {mem_array[word_num]:#0x}") f"get {mem_array[word_num]:#0x}", flush=True)
return 1 return 1
curr_progress = int((word_num * 50) / len(words)) curr_progress = int((word_num * 50) / len(words))
if print_progress and (curr_progress > progress): if print_progress and (curr_progress > progress):
print("#"*(curr_progress - progress), end="", flush=True) print("#"*(curr_progress - progress), end="", flush=True)
progress = curr_progress progress = curr_progress
if print_progress: if print_progress:
print("]") print("]", flush=True)
print("EEPROM check through APB done!") print("EEPROM check through APB done!", flush=True)
return 0 return 0
def write_words(words: List[int], openocd: OpenOcdTclRpc, write_by_word = False, read_through_apb = False, is_resume=True) -> int: def write_words(words: List[int], openocd: OpenOcdTclRpc, write_by_word=False, read_through_apb=False, is_resume=True) -> int:
""" """
Write words in MIK32 EEPROM through APB bus Write words in MIK32 EEPROM through APB bus
@ -213,19 +223,20 @@ def write_words(words: List[int], openocd: OpenOcdTclRpc, write_by_word = False,
@return: return 0 if successful, 1 if failed @return: return 0 if successful, 1 if failed
""" """
print(f"Write {len(words*4)} bytes") print(f"Write {len(words*4)} bytes", flush=True)
openocd.halt() openocd.halt()
eeprom_sysinit(openocd) eeprom_sysinit(openocd)
eeprom_global_erase(openocd) eeprom_global_erase(openocd)
# eeprom_global_erase_check(openocd) # eeprom_global_erase_check(openocd)
openocd.write_word(EEPROM_REGS_NCYCRL, 1<<EEPROM_N_LD_S | 3<<EEPROM_N_R_1_S | 1<<EEPROM_N_R_2_S) openocd.write_word(EEPROM_REGS_NCYCRL, 1 << EEPROM_N_LD_S |
3 << EEPROM_N_R_1_S | 1 << EEPROM_N_R_2_S)
openocd.write_word(EEPROM_REGS_NCYCEP1, 100000) openocd.write_word(EEPROM_REGS_NCYCEP1, 100000)
openocd.write_word(EEPROM_REGS_NCYCEP2, 1000) openocd.write_word(EEPROM_REGS_NCYCEP2, 1000)
time.sleep(0.1) time.sleep(0.1)
word_num:int = 0 word_num: int = 0
progress:int = 0 progress: int = 0
print("EEPROM writing...") print("EEPROM writing...", flush=True)
print("[", end="", flush=True) print("[", end="", flush=True)
if write_by_word: if write_by_word:
for word in words: for word in words:
@ -253,47 +264,53 @@ def write_words(words: List[int], openocd: OpenOcdTclRpc, write_by_word = False,
print("#"*(curr_progress - progress), end="", flush=True) print("#"*(curr_progress - progress), end="", flush=True)
progress = curr_progress progress = curr_progress
eeprom_write_page(openocd, page_num*page_size*4, page) eeprom_write_page(openocd, page_num*page_size*4, page)
print("]") print("]", flush=True)
if read_through_apb: if read_through_apb:
result = eeprom_check_data_apb(openocd, words, 0) result = eeprom_check_data_apb(openocd, words, 0)
else: else:
result = eeprom_check_data_ahb_lite(openocd, words, 0) result = eeprom_check_data_ahb_lite(openocd, words, 0)
if is_resume: if is_resume:
openocd.resume(0) openocd.resume(0)
if result == 0: if result == 0:
print("EEPROM write file done!") print("EEPROM write file done!", flush=True)
return result return result
def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, read_through_apb = False, is_resume=True) -> int: def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, read_through_apb=False, is_resume=True) -> int:
result = 0 result = 0
openocd.halt() openocd.halt()
eeprom_sysinit(openocd) eeprom_sysinit(openocd)
eeprom_global_erase(openocd) eeprom_global_erase(openocd)
# eeprom_global_erase_check(openocd) # eeprom_global_erase_check(openocd)
openocd.write_word(EEPROM_REGS_NCYCRL, 1<<EEPROM_N_LD_S | 3<<EEPROM_N_R_1_S | 1<<EEPROM_N_R_2_S) openocd.write_word(EEPROM_REGS_NCYCRL, 1 << EEPROM_N_LD_S |
3 << EEPROM_N_R_1_S | 1 << EEPROM_N_R_2_S)
openocd.write_word(EEPROM_REGS_NCYCEP1, 100000) openocd.write_word(EEPROM_REGS_NCYCEP1, 100000)
openocd.write_word(EEPROM_REGS_NCYCEP2, 1000) openocd.write_word(EEPROM_REGS_NCYCEP2, 1000)
time.sleep(0.1) time.sleep(0.1)
print("EEPROM writing...") print("EEPROM writing...", flush=True)
for page_offset in list(pages): pages_offsets = list(pages)
for index, page_offset in enumerate(pages_offsets):
page_words = bytes2words(pages[page_offset]) page_words = bytes2words(pages[page_offset])
eeprom_write_page(openocd, page_offset, page_words) eeprom_write_page(openocd, page_offset, page_words,
f"{(index*100)//pages_offsets.__len__()}%")
if read_through_apb: if read_through_apb:
result = eeprom_check_data_apb(openocd, page_words, page_offset, False) result = eeprom_check_data_apb(
openocd, page_words, page_offset, False)
else: else:
result = eeprom_check_data_ahb_lite(openocd, page_words, page_offset, False) result = eeprom_check_data_ahb_lite(
openocd, page_words, page_offset, False)
if result == 1: if result == 1:
print("Page mismatch!") print("Page mismatch!", flush=True)
return result return result
if is_resume: if is_resume:
openocd.resume(0) openocd.resume(0)
if result == 0: if result == 0:
print("EEPROM write file done!") print("EEPROM page recording completed", flush=True)
return result return result

View File

@ -221,7 +221,7 @@ def spifi_intrq_clear(openocd: OpenOcdTclRpc):
def spifi_init(openocd: OpenOcdTclRpc): def spifi_init(openocd: OpenOcdTclRpc):
print("MCU clock init") print("MCU clock init", flush=True)
openocd.write_word(WU_BASE_ADDRESS + WU_Clocks_OFFSET, 0x202) openocd.write_word(WU_BASE_ADDRESS + WU_Clocks_OFFSET, 0x202)
openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_P_Set_OFFSET, 0xffffffff) openocd.write_word(PM_BASE_ADDRESS + PM_Clk_APB_P_Set_OFFSET, 0xffffffff)
@ -231,7 +231,8 @@ def spifi_init(openocd: OpenOcdTclRpc):
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(SPIFI_CONFIG_STAT) | openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(SPIFI_CONFIG_STAT) |
SPIFI_CONFIG_STAT_INTRQ_M | SPIFI_CONFIG_STAT_INTRQ_M |
SPIFI_CONFIG_STAT_RESET_M) SPIFI_CONFIG_STAT_RESET_M)
openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S)) openocd.write_word(SPIFI_CONFIG_CTRL, openocd.read_word(
SPIFI_CONFIG_CTRL) | (7 << SPIFI_CONFIG_CTRL_SCK_DIV_S))
openocd.write_word(SPIFI_CONFIG_ADDR, 0x00) openocd.write_word(SPIFI_CONFIG_ADDR, 0x00)
openocd.write_word(SPIFI_CONFIG_IDATA, 0x00) openocd.write_word(SPIFI_CONFIG_IDATA, 0x00)
openocd.write_word(SPIFI_CONFIG_CLIMIT, 0x00) openocd.write_word(SPIFI_CONFIG_CLIMIT, 0x00)
@ -285,7 +286,7 @@ def spifi_wait_busy(openocd: OpenOcdTclRpc):
def spifi_chip_erase(openocd: OpenOcdTclRpc): def spifi_chip_erase(openocd: OpenOcdTclRpc):
print("Chip erase...") print("Chip erase...", flush=True)
# spifi_intrq_clear(openocd) # spifi_intrq_clear(openocd)
openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word( openocd.write_word(SPIFI_CONFIG_STAT, openocd.read_word(
SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M) SPIFI_CONFIG_STAT) | SPIFI_CONFIG_STAT_INTRQ_M)
@ -296,7 +297,7 @@ def spifi_chip_erase(openocd: OpenOcdTclRpc):
def spifi_sector_erase(openocd: OpenOcdTclRpc, address: int): def spifi_sector_erase(openocd: OpenOcdTclRpc, address: int):
print("Erase sector %s..." % hex(address)) print("Erase sector %s..." % hex(address), flush=True)
openocd.write_word(SPIFI_CONFIG_ADDR, address) openocd.write_word(SPIFI_CONFIG_ADDR, address)
spifi_intrq_clear(openocd) spifi_intrq_clear(openocd)
@ -326,14 +327,15 @@ def spifi_read_data(openocd: OpenOcdTclRpc, address: int, byte_count: int, bin_d
for i in range(byte_count): for i in range(byte_count):
if read_data[i] != bin_data[i]: if read_data[i] != bin_data[i]:
print(f"DATA[{i+address}] = {read_data[i]:#0x} - ошибка") print(
f"DATA[{i+address}] = {read_data[i]:#0x} - ошибка", flush=True)
return 1 return 1
return 0 return 0
def spifi_page_program(openocd: OpenOcdTclRpc, ByteAddress: int, data: List[int], byte_count: int): def spifi_page_program(openocd: OpenOcdTclRpc, ByteAddress: int, data: List[int], byte_count: int, progress: str = ""):
print(f"Writing page {ByteAddress:#010x}...") print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True)
if byte_count > 256: if byte_count > 256:
raise Exception("Byte count more than 256") raise Exception("Byte count more than 256")
@ -389,7 +391,7 @@ def spifi_write(openocd: OpenOcdTclRpc, address: int, data: List[int], data_len:
def spifi_write_file(bytes: List[int], openocd: OpenOcdTclRpc, is_resume=True): def spifi_write_file(bytes: List[int], openocd: OpenOcdTclRpc, is_resume=True):
# print(bytes) # print(bytes)
print(f"Write {len(bytes)} bytes") print(f"Write {len(bytes)} bytes")
openocd.halt() openocd.halt()
spifi_init(openocd) spifi_init(openocd)
spifi_erase(openocd) spifi_erase(openocd)
@ -413,12 +415,12 @@ def spifi_write_file(bytes: List[int], openocd: OpenOcdTclRpc, is_resume=True):
print("end") print("end")
if is_resume: if is_resume:
openocd.resume(0) openocd.resume(0)
return 0 return 0
def spifi_quad_page_program(openocd: OpenOcdTclRpc, ByteAddress: int, data: List[int], byte_count: int): def spifi_quad_page_program(openocd: OpenOcdTclRpc, ByteAddress: int, data: List[int], byte_count: int, progress: str = ""):
print(f"Writing page {ByteAddress:#010x}...") print(f"Writing page {ByteAddress:#010x}... {progress}", flush=True)
if byte_count > 256: if byte_count > 256:
raise Exception("Byte count more than 256") raise Exception("Byte count more than 256")
@ -474,7 +476,8 @@ def spifi_quad_disable(openocd):
(1 << SPIFI_CONFIG_CMD_DOUT_S) | (1 << SPIFI_CONFIG_CMD_DOUT_S) |
(0 << SPIFI_CONFIG_CMD_POLL_S) | (0 << SPIFI_CONFIG_CMD_POLL_S) |
(1 << SPIFI_CONFIG_CMD_DATALEN_S)) (1 << SPIFI_CONFIG_CMD_DATALEN_S))
openocd.write_memory(SPIFI_CONFIG_DATA32, 8, [sreg2 & (~SREG2_QUAD_ENABLE_M)]) openocd.write_memory(SPIFI_CONFIG_DATA32, 8, [
sreg2 & (~SREG2_QUAD_ENABLE_M)])
spifi_wait_busy(openocd) spifi_wait_busy(openocd)
@ -488,30 +491,35 @@ def get_segments_list(pages_offsets: List[int], segment_size: int) -> List[int]:
def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, is_resume=True, use_quad_spi=False, use_chip_erase=False): def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, is_resume=True, use_quad_spi=False, use_chip_erase=False):
result = 0 result = 0
openocd.halt() openocd.halt()
spifi_init(openocd) spifi_init(openocd)
if use_chip_erase: if use_chip_erase:
spifi_erase(openocd, EraseType.CHIP_ERASE) spifi_erase(openocd, EraseType.CHIP_ERASE)
else: else:
spifi_erase(openocd, EraseType.SECTOR_ERASE, get_segments_list(list(pages), 4*1024)) spifi_erase(openocd, EraseType.SECTOR_ERASE,
get_segments_list(list(pages), 4*1024))
address = 0 address = 0
spifi_quad_disable(openocd) spifi_quad_disable(openocd)
# spifi_quad_enable(openocd) # spifi_quad_enable(openocd)
for page_offset in list(pages): pages_offsets = list(pages)
for index, page_offset in enumerate(pages_offsets):
page_bytes = pages[page_offset] page_bytes = pages[page_offset]
spifi_write_enable(openocd) spifi_write_enable(openocd)
if (use_quad_spi): if (use_quad_spi):
spifi_quad_page_program(openocd, page_offset, page_bytes, 256) spifi_quad_page_program(
openocd, page_offset, page_bytes, 256, f"{(index*100)//pages_offsets.__len__()}%")
else: else:
spifi_page_program(openocd, page_offset, page_bytes, 256) spifi_page_program(openocd, page_offset, page_bytes,
256, f"{(index*100)//pages_offsets.__len__()}%")
spifi_wait_busy(openocd) spifi_wait_busy(openocd)
result = spifi_read_data(openocd, page_offset, 256, page_bytes) result = spifi_read_data(openocd, page_offset, 256, page_bytes)
if result == 1: if result == 1:
print("Data error") print("Data error")
return result return result
@ -520,5 +528,5 @@ def write_pages(pages: Dict[int, List[int]], openocd: OpenOcdTclRpc, is_resume=T
if is_resume: if is_resume:
openocd.resume(0) openocd.resume(0)
return 0 return 0