docs: def readStoredSms(self, index, memory=None):
          """ Reads and returns the SMS message at the specified index
          
          :param index: The index of the SMS message in the specified memory
          :type index: int
          :param memory: The memory type to read from. If None, use the current default SMS read memory
          :type memory: str or None
          
          :raise CommandError: if unable to read the stored message
          
          :return: The SMS message
          :rtype: subclass of gsmmodem.modem.Sms (either ReceivedSms or StatusReport)
          """
          # Switch to the correct memory type if required
          self._setSmsMemory(readDelete=memory)
          msgData = self.write('AT+CMGR={0}'.format(index))
          # Parse meta information
          if self._smsTextMode:
              cmgrMatch = self.CMGR_SM_DELIVER_REGEX_TEXT.match(msgData[0])
              if cmgrMatch:
                  msgStatus, number, msgTime = cmgrMatch.groups()
                  msgText = '\n'.join(msgData[1:-1])
                  return ReceivedSms(self, Sms.TEXT_MODE_STATUS_MAP[msgStatus], number, parseTextModeTimeStr(msgTime), msgText)
              else:
                  # Try parsing status report
                  cmgrMatch = self.CMGR_SM_REPORT_REGEXT_TEXT.match(msgData[0])
                  if cmgrMatch:
                      msgStatus, reference, number, sentTime, deliverTime, deliverStatus = cmgrMatch.groups()
                      if msgStatus.startswith('"'):
                          msgStatus = msgStatus[1:-1]                    
                      if len(msgStatus) == 0:
                          msgStatus = "REC UNREAD"
                      return StatusReport(self, Sms.TEXT_MODE_STATUS_MAP[msgStatus], int(reference), number, parseTextModeTimeStr(sentTime), parseTextModeTimeStr(deliverTime), int(deliverStatus))
                  else:
                      raise CommandError('Failed to parse text-mode SMS message +CMGR response: {0}'.format(msgData))
          else:
              cmgrMatch = self.CMGR_REGEX_PDU.match(msgData[0])
              if not cmgrMatch:
                  raise CommandError('Failed to parse PDU-mode SMS message +CMGR response: {0}'.format(msgData))
              stat, alpha, length = cmgrMatch.groups()
              try:
                  stat = int(stat)
              except Exception:
                  # Some modems (ZTE) do not always read return status - default to RECEIVED UNREAD
                  stat = Sms.STATUS_RECEIVED_UNREAD
              pdu = msgData[1]
              smsDict = decodeSmsPdu(pdu)
              if smsDict['type'] == 'SMS-DELIVER':
                  return ReceivedSms(self, int(stat), smsDict['number'], smsDict['time'], smsDict['text'], smsDict['smsc'])
              elif smsDict['type'] == 'SMS-STATUS-REPORT':
                  return StatusReport(self, int(stat), smsDict['reference'], smsDict['number'], smsDict['time'], smsDict['discharge'], smsDict['status'])
              else:
                  raise CommandError('Invalid PDU type for readStoredSms(): {0}'.format(smsDict['type']))