Move "suspend_uicc" command from pySim-shell to ts_102_221.py

The SUSPEND UICC command is a TS 102 221 (UICC) command, so move
it to the UICC Card Profile.

Also, make sure that any shell command sets specified in the
CardProfile are actually installed during equip().

Change-Id: I574348951f06b749aeff986589186110580328bc
diff --git a/docs/shell.rst b/docs/shell.rst
index 510f4c6..8f85246 100644
--- a/docs/shell.rst
+++ b/docs/shell.rst
@@ -199,6 +199,11 @@
    :func: Iso7816Commands.close_chan_parser
 
 
+TS 102 221 commands
+-------------------
+
+These are commands as specified in ETSI TS 102 221, the core UICC specification.
+
 suspend_uicc
 ~~~~~~~~~~~~
 This command allows you to perform the SUSPEND UICC command on the card.  This is a relatively
@@ -209,8 +214,8 @@
 including the electrical power down.
 
 .. argparse::
-   :module: pySim-shell
-   :func: Iso7816Commands.suspend_uicc_parser
+   :module: pySim.ts_102_221
+   :func: CardProfileUICC.AddlShellCommands.suspend_uicc_parser
 
 
 
diff --git a/pySim-shell.py b/pySim-shell.py
index d6d9a64..3f0818a 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -219,6 +219,9 @@
             self._onchange_conserve_write(
                 'conserve_write', False, self.conserve_write)
             self._onchange_apdu_trace('apdu_trace', False, self.apdu_trace)
+            if self.rs.profile:
+                for cmd_set in self.rs.profile.shell_cmdsets:
+                    self.register_command_set(cmd_set)
             self.register_command_set(Iso7816Commands())
             self.register_command_set(Ts102222Commands())
             self.register_command_set(PySimCommands())
@@ -283,6 +286,9 @@
     @cmd2.with_category(CUSTOM_CATEGORY)
     def do_equip(self, opts):
         """Equip pySim-shell with card"""
+        if self.rs.profile:
+            for cmd_set in self.rs.profile.shell_cmdsets:
+                self.unregister_command_set(cmd_set)
         rs, card = init_card(sl)
         self.equip(card, rs)
 
@@ -934,20 +940,6 @@
         fcp_dec = self._cmd.lchan.status()
         self._cmd.poutput_json(fcp_dec)
 
-    suspend_uicc_parser = argparse.ArgumentParser()
-    suspend_uicc_parser.add_argument('--min-duration-secs', type=int, default=60,
-                                     help='Proposed minimum duration of suspension')
-    suspend_uicc_parser.add_argument('--max-duration-secs', type=int, default=24*60*60,
-                                     help='Proposed maximum duration of suspension')
-
-    # not ISO7816-4 but TS 102 221
-    @cmd2.with_argparser(suspend_uicc_parser)
-    def do_suspend_uicc(self, opts):
-        """Perform the SUSPEND UICC command. Only supported on some UICC."""
-        (duration, token, sw) = self._cmd.card._scc.suspend_uicc(min_len_secs=opts.min_duration_secs,
-                                                                 max_len_secs=opts.max_duration_secs)
-        self._cmd.poutput(
-            'Negotiated Duration: %u secs, Token: %s, SW: %s' % (duration, token, sw))
 
 class Proact(ProactiveHandler):
     def receive_fetch(self, pcmd: ProactiveCommand):
diff --git a/pySim/ts_102_221.py b/pySim/ts_102_221.py
index b8db5c9..bade9cf 100644
--- a/pySim/ts_102_221.py
+++ b/pySim/ts_102_221.py
@@ -838,7 +838,8 @@
         }
 
         super().__init__(name, desc='ETSI TS 102 221', cla="00",
-                         sel_ctrl="0004", files_in_mf=files, sw=sw)
+                         sel_ctrl="0004", files_in_mf=files, sw=sw,
+                         shell_cmdsets = [self.AddlShellCommands()])
 
     @staticmethod
     def decode_select_response(resp_hex: str) -> object:
@@ -852,6 +853,23 @@
     def match_with_card(scc: SimCardCommands) -> bool:
         return match_uicc(scc)
 
+    @with_default_category('TS 102 221 Specific Commands')
+    class AddlShellCommands(CommandSet):
+        suspend_uicc_parser = argparse.ArgumentParser()
+        suspend_uicc_parser.add_argument('--min-duration-secs', type=int, default=60,
+                                         help='Proposed minimum duration of suspension')
+        suspend_uicc_parser.add_argument('--max-duration-secs', type=int, default=24*60*60,
+                                         help='Proposed maximum duration of suspension')
+
+        # not ISO7816-4 but TS 102 221
+        @cmd2.with_argparser(suspend_uicc_parser)
+        def do_suspend_uicc(self, opts):
+            """Perform the SUSPEND UICC command. Only supported on some UICC."""
+            (duration, token, sw) = self._cmd.card._scc.suspend_uicc(min_len_secs=opts.min_duration_secs,
+                                                                     max_len_secs=opts.max_duration_secs)
+            self._cmd.poutput(
+                'Negotiated Duration: %u secs, Token: %s, SW: %s' % (duration, token, sw))
+
 
 class CardProfileUICCSIM(CardProfileUICC):
     """Same as above, but including 2G SIM support"""