commands: conserve write cycles

When a record or a binary file is written the card goes throth a full
flash/eeprom write cycle at this location, even when the data does not
change. This can be optimized by reading before writing in order to
compere if the data we are about to write is actually different.

Change-Id: Ifd1b80d3ede15a7caa29077a37ac7cf58c9053f1
Related: OS#4963
This commit is contained in:
Philipp Maier 2021-03-17 17:19:52 +01:00 committed by Harald Welte
parent 2b11c32e20
commit 38c74f6d41
3 changed files with 28 additions and 5 deletions

View File

@ -67,11 +67,17 @@ class PysimApp(cmd2.Cmd):
self.numeric_path = False
self.add_settable(cmd2.Settable('numeric_path', bool, 'Print File IDs instead of names',
onchange_cb=self._onchange_numeric_path))
self.conserve_write = True
self.add_settable(cmd2.Settable('conserve_write', bool, 'Read and compare before write',
onchange_cb=self._onchange_conserve_write))
self.update_prompt()
def _onchange_numeric_path(self, param_name, old, new):
self.update_prompt()
def _onchange_conserve_write(self, param_name, old, new):
self.rs.conserve_write = new
def update_prompt(self):
path_list = self.rs.selected_file.fully_qualified_path(not self.numeric_path)
self.prompt = 'pySIM-shell (%s)> ' % ('/'.join(path_list))

View File

@ -144,9 +144,17 @@ class SimCardCommands(object):
raise ValueError('Failed to read (offset %d)' % (offset))
return total_data, sw
def update_binary(self, ef, data, offset=0, verify=False):
def update_binary(self, ef, data, offset=0, verify=False, conserve=False):
data_length = len(data) // 2
# Save write cycles by reading+comparing before write
if conserve:
data_current, sw = self.read_binary(ef, data_length, offset)
if data_current == data:
return None, sw
self.select_path(ef)
pdu = self.cla_byte + 'd6%04x%02x' % (offset, len(data) // 2) + data
pdu = self.cla_byte + 'd6%04x%02x' % (offset, data_length) + data
res = self._tp.send_apdu_checksw(pdu)
if verify:
self.verify_binary(ef, data, offset)
@ -163,7 +171,7 @@ class SimCardCommands(object):
pdu = self.cla_byte + 'b2%02x04%02x' % (rec_no, rec_length)
return self._tp.send_apdu(pdu)
def update_record(self, ef, rec_no, data, force_len=False, verify=False):
def update_record(self, ef, rec_no, data, force_len=False, verify=False, conserve=False):
r = self.select_path(ef)
if not force_len:
rec_length = self.__record_len(r)
@ -171,6 +179,14 @@ class SimCardCommands(object):
raise ValueError('Invalid data length (expected %d, got %d)' % (rec_length, len(data) // 2))
else:
rec_length = len(data) // 2
# Save write cycles by reading+comparing before write
if conserve:
data_current, sw = self.read_record(ef, rec_no)
data_current = data_current[0:rec_length*2]
if data_current == data:
return None, sw
pdu = (self.cla_byte + 'dc%02x04%02x' % (rec_no, rec_length)) + data
res = self._tp.send_apdu_checksw(pdu)
if verify:

View File

@ -566,6 +566,7 @@ class RuntimeState(object):
self.mf.add_application(a)
for f in self.profile.files_in_mf:
self.mf.add_file(f)
self.conserve_write = True
def _match_applications(self):
"""match the applications from the profile with applications on the card"""
@ -699,7 +700,7 @@ class RuntimeState(object):
def update_binary(self, data_hex, offset=0):
if not isinstance(self.selected_file, TransparentEF):
raise TypeError("Only works with TransparentEF")
return self.card._scc.update_binary(self.selected_file.fid, data_hex, offset)
return self.card._scc.update_binary(self.selected_file.fid, data_hex, offset, conserve=self.conserve_write)
def update_binary_dec(self, data):
data_hex = self.selected_file.encode_hex(data)
@ -719,7 +720,7 @@ class RuntimeState(object):
def update_record(self, rec_nr, data_hex):
if not isinstance(self.selected_file, LinFixedEF):
raise TypeError("Only works with Linear Fixed EF")
return self.card._scc.update_record(self.selected_file.fid, rec_nr, data_hex)
return self.card._scc.update_record(self.selected_file.fid, rec_nr, data_hex, conserve=self.conserve_write)
def update_record_dec(self, rec_nr, data):
hex_data = self.selected_file.encode_record_hex(data)