filesystem: Introduce the basic notion of 'logical channels'

cards can have multiple logical channels; each logical channel
has its own state of what is the current selected file + application.

Let's split the RuntimeState class into the global RuntimeState and the
per-lchan-specific RuntimeLchan class.

This code doesn't actually introduce any code that uses lchans other
than the basic logical channel (0), but just modifies the data model
to accomodate those in the future.

Change-Id: I7aa994b625467d4e46a2edd8123240b930305360
diff --git a/pySim/ts_102_222.py b/pySim/ts_102_222.py
index 3c57e5b..4843c77 100644
--- a/pySim/ts_102_222.py
+++ b/pySim/ts_102_222.py
@@ -51,12 +51,12 @@
         if not opts.force_delete:
             self._cmd.perror("Refusing to permanently delete the file, please read the help text.")
             return
-        f = self._cmd.rs.get_file_for_selectable(opts.NAME)
+        f = self._cmd.lchan.get_file_for_selectable(opts.NAME)
         (data, sw) = self._cmd.card._scc.delete_file(f.fid)
 
     def complete_delete_file(self, text, line, begidx, endidx) -> List[str]:
         """Command Line tab completion for DELETE FILE"""
-        index_dict = {1: self._cmd.rs.selected_file.get_selectable_names()}
+        index_dict = {1: self._cmd.lchan.selected_file.get_selectable_names()}
         return self._cmd.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)
 
     termdf_parser = argparse.ArgumentParser()
@@ -72,12 +72,12 @@
         if not opts.force:
             self._cmd.perror("Refusing to terminate the file, please read the help text.")
             return
-        f = self._cmd.rs.get_file_for_selectable(opts.NAME)
+        f = self._cmd.lchan.get_file_for_selectable(opts.NAME)
         (data, sw) = self._cmd.card._scc.terminate_df(f.fid)
 
     def complete_terminate_df(self, text, line, begidx, endidx) -> List[str]:
         """Command Line tab completion for TERMINATE DF"""
-        index_dict = {1: self._cmd.rs.selected_file.get_selectable_names()}
+        index_dict = {1: self._cmd.lchan.selected_file.get_selectable_names()}
         return self._cmd.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)
 
     @cmd2.with_argparser(termdf_parser)
@@ -88,12 +88,12 @@
         if not opts.force:
             self._cmd.perror("Refusing to terminate the file, please read the help text.")
             return
-        f = self._cmd.rs.get_file_for_selectable(opts.NAME)
+        f = self._cmd.lchan.get_file_for_selectable(opts.NAME)
         (data, sw) = self._cmd.card._scc.terminate_ef(f.fid)
 
     def complete_terminate_ef(self, text, line, begidx, endidx) -> List[str]:
         """Command Line tab completion for TERMINATE EF"""
-        index_dict = {1: self._cmd.rs.selected_file.get_selectable_names()}
+        index_dict = {1: self._cmd.lchan.selected_file.get_selectable_names()}
         return self._cmd.index_based_complete(text, line, begidx, endidx, index_dict=index_dict)
 
     tcard_parser = argparse.ArgumentParser()
@@ -154,7 +154,7 @@
         fcp = FcpTemplate(children=ies)
         (data, sw) = self._cmd.card._scc.create_file(b2h(fcp.to_tlv()))
         # the newly-created file is automatically selected but our runtime state knows nothing of it
-        self._cmd.rs.select_file(self._cmd.rs.selected_file)
+        self._cmd.lchan.select_file(self._cmd.lchan.selected_file)
 
     createdf_parser = argparse.ArgumentParser()
     createdf_parser.add_argument('FILE_ID', type=str, help='File Identifier as 4-character hex string')
@@ -205,4 +205,4 @@
         fcp = FcpTemplate(children=ies)
         (data, sw) = self._cmd.card._scc.create_file(b2h(fcp.to_tlv()))
         # the newly-created file is automatically selected but our runtime state knows nothing of it
-        self._cmd.rs.select_file(self._cmd.rs.selected_file)
+        self._cmd.lchan.select_file(self._cmd.lchan.selected_file)