Skip to content

Commit

Permalink
Merge pull request #174 from Luos-io/feat/boot_protection
Browse files Browse the repository at this point in the history
[Bootloader] Add protection: resend message in case of fail
  • Loading branch information
JeromeGalan authored Dec 15, 2022
2 parents 1fbfc5b + e2d68d8 commit b1676a6
Showing 1 changed file with 129 additions and 0 deletions.
129 changes: 129 additions & 0 deletions pyluos/tools/bootloader.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,30 @@ def erase_flash(device, topic, nodes_to_program):
print(u"\r\n ╰> Flash memory of node ", response['node'], " erased.")
state = device._poll_once()

# retry sending failed messages
for node in failed_nodes:
send_node_command(device, node, topic, BOOTLOADER_ERASE)
print(u"\r\n ╰> Retry erase memory of node ", node)
init_time = time.time()
state = device._poll_once()
while len(failed_nodes):
if(time.time() - init_time > ERASE_TIMEOUT):
return_value = False
break

# check if it is a response message
if 'bootloader' in state:
for response in state['bootloader']:
if (response['response'] == BOOTLOADER_ERASE_RESP):
# this node responded, delete it from the failed nodes list
if response['node'] in failed_nodes:
failed_nodes.remove(response['node'])
print(u"\r\n ╰> Flash memory of node ", response['node'], " erased.")
state = device._poll_once()

if not len(failed_nodes):
return_value = True

waiting_bg.terminate()
return return_value, failed_nodes

Expand Down Expand Up @@ -358,6 +382,32 @@ def send_frame_from_binary(device, topic, frame_size, file_offset, nodes_to_prog
failed_nodes.remove(response['node'])
# wait for next message
state = device._poll_once()

for node in failed_nodes:
# retry sending failed messages
send_data_node(device, node, BOOTLOADER_BIN_CHUNK, frame_size, data_bytes)
state = device._poll_once()
print(u"\r\n ╰> Retry sending binary message to node ", node)
init_time = time.time()
while len(failed_nodes):
# check for timeout of nodes
if(time.time() - init_time > PROGRAM_TIMEOUT):
return_value = False
break

# check if it is a response message
if 'bootloader' in state:
for response in state['bootloader']:
if (response['response'] == BOOTLOADER_BIN_CHUNK_RESP):
# the node responsed, remove it for fails list
if response['node'] in failed_nodes:
failed_nodes.remove(response['node'])
# wait for next message
state = device._poll_once()

if not len(failed_nodes):
return_value = True

return return_value, failed_nodes

# *******************************************************************************
Expand All @@ -379,6 +429,25 @@ def send_data(device, topic, command, size, data):
# send json command
device._write(json.dumps(bootloader_cmd).encode() + '\n'.encode() + data)

# *******************************************************************************
# @brief send binary data with a header to a specific node
# @param
# @return None
# *******************************************************************************
def send_data_node(device, node, command, size, data):
# create a json file with the list of the nodes to program
bootloader_cmd = {
'bootloader': {
'command': {
'size': [size],
'type': command,
'node': node,
},
}
}
# send json command
device._write(json.dumps(bootloader_cmd).encode() + '\n'.encode() + data)

# *******************************************************************************
# @brief send the binary end command
# @param
Expand Down Expand Up @@ -411,6 +480,31 @@ def send_binary_end(device, topic, nodes_to_program):
failed_nodes.remove(response['node'])
state = device._poll_once()

for node in failed_nodes:
# retry sending failed messages
send_node_command(device, node, topic, BOOTLOADER_BIN_END)
print(u"\r\n ╰> Retry sending end message to node ", node)
state = device._poll_once()
init_time = time.time()
while len(failed_nodes):
# check for timeout of nodes
if(time.time() - init_time > RESP_TIMEOUT):
return_value = False
break

# check if it is a response message
if 'bootloader' in state:
for response in state['bootloader']:
if (response['response'] == BOOTLOADER_BIN_END_RESP):
# the node responsed, remove it for fails list
if response['node'] in failed_nodes:
failed_nodes.remove(response['node'])
# wait for next message
state = device._poll_once()

if not len(failed_nodes):
return_value = True

return return_value, failed_nodes

# *******************************************************************************
Expand Down Expand Up @@ -475,6 +569,41 @@ def check_crc(device, topic, nodes_to_program):
return_value = False
state = device._poll_once()

for node in failed_nodes:
# retry sending failed messages
send_node_command(device, node, topic, BOOTLOADER_CRC_TEST)
print(u"\r\n ╰> Retry sending crc demand to node ", node)
state = device._poll_once()
init_time = time.time()
while len(failed_nodes):
# check for timeout of nodes
if(time.time() - init_time > RESP_TIMEOUT):
return_value = False
break

# check if it is a response message
if 'bootloader' in state:
for response in state['bootloader']:
if (response['response'] == BOOTLOADER_CRC_RESP):
source_crc = int.from_bytes(compute_crc(), byteorder='big')
node_crc = response['crc_value']
node_id = response['node']
# crc properly received
if (source_crc == node_crc):
print(u" ╰> CRC test for node", node_id, " : OK.")
if node_id in failed_nodes:
timeout -= RESP_TIMEOUT
failed_nodes.remove(node_id)
else:
# not a good crc
print(u" ╰> CRC test for node", node_id, ": NOK.")
print(u" ╰> waited :", hex(source_crc), ", received :", hex(node_crc))
return_value = False
state = device._poll_once()

if not len(failed_nodes):
return_value = True

return return_value, failed_nodes

# *******************************************************************************
Expand Down

0 comments on commit b1676a6

Please sign in to comment.