error_t mqttSnClientSubscribe(MqttSnClientContext *context,
   const char_t *topicName, MqttSnQosLevel qos)
{
   error_t error;
   systime_t time;

   //Check parameters
   if(context == NULL || topicName == NULL)
      return ERROR_INVALID_PARAMETER;

   //Initialize status code
   error = NO_ERROR;

   //Topic subscribe procedure
   while(!error)
   {
      //Get current time
      time = osGetSystemTime();

      //Check current state
      if(context->state == MQTT_SN_CLIENT_STATE_ACTIVE)
      {
         //The message identifier allows the sender to match a message with
         //its corresponding acknowledgment
         mqttSnClientGenerateMessageId(context);

         //Save current time
         context->startTime = time;

         //Send SUBSCRIBE message
         error = mqttSnClientSendSubscribe(context, topicName, qos);
      }
      else if(context->state == MQTT_SN_CLIENT_STATE_SENDING_REQ)
      {
         //Check whether the timeout has elapsed
         if(timeCompare(time, context->startTime + context->timeout) >= 0)
         {
            //Abort the retransmission procedure
            context->state = MQTT_SN_CLIENT_STATE_DISCONNECTING;
            //Report a timeout error
            error = ERROR_TIMEOUT;
         }
         else if(timeCompare(time, context->retransmitStartTime +
            MQTT_SN_CLIENT_RETRY_TIMEOUT) >= 0)
         {
            //If the retry timer times out and the expected gateway's reply
            //is not received, the client retransmits the message
            error = mqttSnClientSendSubscribe(context, topicName, qos);
         }
         else
         {
            //Wait for the gateway's reply
            error = mqttSnClientProcessEvents(context, MQTT_SN_CLIENT_TICK_INTERVAL);
         }
      }
      else if(context->state == MQTT_SN_CLIENT_STATE_RESP_RECEIVED)
      {
         //Update MQTT-SN client state
         context->state = MQTT_SN_CLIENT_STATE_ACTIVE;

         //Check the type of the received message
         if(context->msgType == MQTT_SN_MSG_TYPE_SUBACK)
         {
            //If the subscribe request has not been accepted, the failure reason
            //is encoded in the return code field of the SUBACK message
            if(context->returnCode == MQTT_SN_RETURN_CODE_ACCEPTED)
            {
               //The topic ID field is not relevant in case of subscriptions to a
               //topic name which contains wildcard characters
               if(strchr(topicName, '#') == NULL && strchr(topicName, '+') == NULL)
               {
                  //Save the topic ID assigned by the gateway
                  error = mqttSnClientAddTopic(context, topicName, context->topicId);
               }

               //A SUBACK message has been received
               break;
            }
            else
            {
               //The subscribe request has been rejected by the gateway
               error = ERROR_REQUEST_REJECTED;
            }
         }
         else
         {
            //Report an error
            error = ERROR_UNEXPECTED_RESPONSE;
         }
      }
      else
      {
         //Invalid state
         error = ERROR_NOT_CONNECTED;
      }
   }

   //Return status code
   return error;
}
error_t mqttSnClientSubscribe(MqttSnClientContext *context,
   const char_t *topicName, MqttSnQosLevel qos)
{
   error_t error;
   systime_t time;

    
   if(context == NULL || topicName == NULL)
      return ERROR_INVALID_PARAMETER;

    
   error = NO_ERROR;

    
   while(!error)
   {
       
      time = osGetSystemTime();

       
      if(context->state == MQTT_SN_CLIENT_STATE_ACTIVE)
      {
          
          
         mqttSnClientGenerateMessageId(context);

          
         context->startTime = time;

          
         error = mqttSnClientSendSubscribe(context, topicName, qos);
      }
      else if(context->state == MQTT_SN_CLIENT_STATE_SENDING_REQ)
      {
          
         if(timeCompare(time, context->startTime + context->timeout) >= 0)
         {
             
            context->state = MQTT_SN_CLIENT_STATE_DISCONNECTING;
             
            error = ERROR_TIMEOUT;
         }
         else if(timeCompare(time, context->retransmitStartTime +
            MQTT_SN_CLIENT_RETRY_TIMEOUT) >= 0)
         {
             
             
            error = mqttSnClientSendSubscribe(context, topicName, qos);
         }
         else
         {
             
            error = mqttSnClientProcessEvents(context, MQTT_SN_CLIENT_TICK_INTERVAL);
         }
      }
      else if(context->state == MQTT_SN_CLIENT_STATE_RESP_RECEIVED)
      {
          
         context->state = MQTT_SN_CLIENT_STATE_ACTIVE;

          
         if(context->msgType == MQTT_SN_MSG_TYPE_SUBACK)
         {
             
             
            if(context->returnCode == MQTT_SN_RETURN_CODE_ACCEPTED)
            {
                
                
               if(strchr(topicName, '#') == NULL && strchr(topicName, '+') == NULL)
               {
                   
                  error = mqttSnClientAddTopic(context, topicName, context->topicId);
               }

                
               break;
            }
            else
            {
                
               error = ERROR_REQUEST_REJECTED;
            }
         }
         else
         {
             
            error = ERROR_UNEXPECTED_RESPONSE;
         }
      }
      else
      {
          
         error = ERROR_NOT_CONNECTED;
      }
   }

    
   return error;
}