Example #1
0
void doBusyWorkForTicks(uint32_t numTicks){
	MQX_TICK_STRUCT currentTime;
	 _time_get_ticks(&currentTime);

	 uint32_t ticksRun = 0;
	 uint32_t currentTicks = currentTime.TICKS[0];
	 uint32_t previousTicks = currentTime.TICKS[0];

	do{
		_time_get_ticks(&currentTime);
		currentTicks = currentTime.TICKS[0];
		if(currentTicks > previousTicks){
			ticksRun++; // The ticks run is only updated if the system clock ticks have increased
			previousTicks = currentTicks;
		}
	}
	while(ticksRun < numTicks);
}
Example #2
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available. The data is NOT copied into the user-app. buffer.
 *
 * This is the "zero-copy receive" version of the MCC receive function. No data is copied. 
 * Only the pointer to the data is returned. This version is fast, but it requires the user to manage
 * buffer allocation. Specifically, the user must decide when a buffer is no longer in use and
 * make the appropriate API call to free it.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to receive from.
 * \param[out] buffer_p Pointer to the MCC buffer of the shared memory where the received data is stored.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of valid bytes in the buffer.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv_copy
 * \see MCC_ENDPOINT
 */
int mcc_recv_nocopy(MCC_ENDPOINT *endpoint, void **buffer_p, MCC_MEM_SIZE *recv_size, unsigned int timeout_us)
{
    MCC_RECEIVE_LIST *list;
    int return_value;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE;
    unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* The endpoint is not valid */
    if(list == null) {
        return MCC_ERR_ENDPOINT;
    }

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_TIMEOUT;
        }
        /* Blocking call */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(timeout_us == 0xFFFFFFFF) {
                _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0);
            }
            /* timeout_us > 0 */
            else {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time);
            }
#endif
            MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));
        }
    }

    /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */
    _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index);

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        return MCC_ERR_TIMEOUT;
	}

    /* Get the message pointer from the head of the receive buffer list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    *buffer_p = (void*)&list->head->data;
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE));
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the endpoint list */
    mcc_dequeue_buffer(list);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Example #3
0
/*!
 * \brief This function receives a message from the specified endpoint if one is available.
 *        The data will be copied from the receive buffer into the user supplied buffer.
 *
 * This is the "receive with copy" version of the MCC receive function. This version is simple
 * to use but it requires copying data from shared memory into the user space buffer.
 * The user has no obligation or burden to manage the shared memory buffers.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to receive from.
 * \param[in] buffer Pointer to the user-app. buffer where data will be copied into.
 * \param[in] buffer_size The maximum number of bytes to copy.
 * \param[out] recv_size Pointer to an MCC_MEM_SIZE that will contain the number of bytes actually copied into the buffer.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a new message came)
 *
 * \see mcc_send
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_recv_copy(MCC_ENDPOINT *endpoint, void *buffer, MCC_MEM_SIZE buffer_size, MCC_MEM_SIZE *recv_size, unsigned int timeout_us)
{
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
    MCC_ENDPOINT tmp_destination = {(MCC_CORE)0, (MCC_NODE)0, (MCC_PORT)0};
    int return_value, i = 0;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    unsigned int lwevent_index = endpoint->port / MCC_MQX_LWEVENT_GROUP_SIZE;
    unsigned int lwevent_group_index = endpoint->port % MCC_MQX_LWEVENT_GROUP_SIZE;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* The endpoint is not valid */
    if(list == null) {
        return MCC_ERR_ENDPOINT;
    }

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_TIMEOUT;
        }
        /* Blocking call */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(timeout_us == 0xFFFFFFFF) {
                _lwevent_wait_ticks(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, 0);
            }
            /* timeout_us > 0 */
            else {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                _lwevent_wait_until(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index, TRUE, &tick_time);
            }
#endif
            MCC_DCACHE_INVALIDATE_MLINES((void*)list, sizeof(MCC_RECEIVE_LIST*));
        }
    }

    /* Clear event bit specified for the particular endpoint in the lwevent_buffer_queued lwevent group */
    _lwevent_clear(&lwevent_buffer_queued[lwevent_index], 1<<lwevent_group_index);

    if(list->head == (MCC_RECEIVE_BUFFER*)0) {
        /* Buffer not dequeued before the timeout */
        return MCC_ERR_TIMEOUT;
    }

    /* Copy the message from the MCC receive buffer into the user-app. buffer */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data_len, sizeof(MCC_MEM_SIZE));
    if (list->head->data_len > buffer_size) {
        list->head->data_len = buffer_size;
    }
    *recv_size = (MCC_MEM_SIZE)(list->head->data_len);
    MCC_DCACHE_INVALIDATE_MLINES((void*)&list->head->data, list->head->data_len);
    mcc_memcpy((void*)list->head->data, buffer, list->head->data_len);

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the endpoint list */
    buf = mcc_dequeue_buffer(list);

    /* Enqueue the buffer into the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    mcc_queue_buffer(&bookeeping_data->free_list, buf);

    /* Notify all cores (except of itself) via CPU-to-CPU interrupt that a buffer has been freed */
    affiliated_signal.type = BUFFER_FREED;
    affiliated_signal.destination = tmp_destination;
    for (i=0; i<MCC_NUM_CORES; i++) {
        if(i != MCC_CORE_NUMBER) {
            mcc_queue_signal(i, affiliated_signal);
        }
    }
    mcc_generate_cpu_to_cpu_interrupt();

    /* Semaphore-protected section end */
    return_value = mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    return return_value;
}
Example #4
0
/*!
 * \brief This function sends a message to an endpoint.
 *
 * The message is copied into the MCC buffer and the destination core is signaled.
 *
 * \param[in] endpoint Pointer to the receiving endpoint to send to.
 * \param[in] msg Pointer to the message to be sent.
 * \param[in] msg_size Size of the message to be sent in bytes.
 * \param[in] timeout_us Timeout, in microseconds, to wait for a free buffer. A value of 0 means don't wait (non-blocking call). A value of 0xffffffff means wait forever (blocking call).
 *
 * \return MCC_SUCCESS
 * \return MCC_ERR_ENDPOINT (the endpoint does not exist)
 * \return MCC_ERR_SEMAPHORE (semaphore handling error)
 * \return MCC_ERR_INVAL (the msg_size exceeds the size of a data buffer)
 * \return MCC_ERR_TIMEOUT (timeout exceeded before a buffer became available)
 * \return MCC_ERR_NOMEM (no free buffer available and timeout_us set to 0)
 * \return MCC_ERR_SQ_FULL (signal queue is full)
 *
 * \see mcc_recv_copy
 * \see mcc_recv_nocopy
 * \see MCC_ENDPOINT
 */
int mcc_send(MCC_ENDPOINT *endpoint, void *msg, MCC_MEM_SIZE msg_size, unsigned int timeout_us)
{
    int return_value, end_time_set_flag = 0;
    MCC_RECEIVE_LIST *list;
    MCC_RECEIVE_BUFFER * buf;
    MCC_SIGNAL affiliated_signal;
#if (MCC_OS_USED == MCC_MQX)
    unsigned int time_us_tmp;
    MQX_TICK_STRUCT tick_time;
#endif

    /* Check if the size of the message to be sent does not exceed the size of the mcc buffer */
    if(msg_size > sizeof(bookeeping_data->r_buffers[0].data)) {
        return MCC_ERR_INVAL;
    }

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Dequeue the buffer from the free list */
    MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
    buf = mcc_dequeue_buffer(&bookeeping_data->free_list);

    while(buf == null) {
        mcc_release_semaphore();

        /* Non-blocking call */
        if(timeout_us == 0) {
            return MCC_ERR_NOMEM;
        }
        /* Blocking calls: CPU-to-CPU ISR sets the event and thus resumes tasks waiting for a free MCC buffer.
         * As the interrupt request is send to all cores when a buffer is freed it could happen that several
         * tasks from different cores/nodes are waiting for a free buffer and all of them are notified that the buffer
         * has been freed. This function has to check (after the wake up) that a buffer is really available and has not been already
         * grabbed by another "competitor task" that has been faster. If so, it has to wait again for the next notification. */
        /* wait forever */
        else if(timeout_us == 0xFFFFFFFF) {
#if (MCC_OS_USED == MCC_MQX)
            _lwevent_wait_ticks(&lwevent_buffer_freed, 1, TRUE, 0);
            _lwevent_clear(&lwevent_buffer_freed, 1);
#endif
        }
        /* timeout_us > 0 */
        else {
#if (MCC_OS_USED == MCC_MQX)
            if(!end_time_set_flag) {
                _time_get_ticks(&tick_time);
                _time_add_usec_to_ticks(&tick_time, timeout_us);
                end_time_set_flag = 1;
            }
            return_value = _lwevent_wait_until(&lwevent_buffer_freed, 1, TRUE, &tick_time);
            if(return_value == LWEVENT_WAIT_TIMEOUT) {
                /* Buffer not dequeued before the timeout */
                return MCC_ERR_TIMEOUT;
            }
            _lwevent_clear(&lwevent_buffer_freed, 1);
#endif
        }
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_get_semaphore();
        buf = mcc_dequeue_buffer(&bookeeping_data->free_list);
    }

    /* Semaphore-protected section end */
    mcc_release_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Copy the message into the MCC receive buffer */
    mcc_memcpy(msg, (void*)buf->data, (unsigned int)msg_size);
    MCC_DCACHE_FLUSH_MLINES((void*)buf->data, msg_size);
    buf->data_len = msg_size;
    MCC_DCACHE_FLUSH_MLINES((void*)&buf->data_len, sizeof(MCC_MEM_SIZE));

    /* Semaphore-protected section start */
    return_value = mcc_get_semaphore();
    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Get list of buffers kept by the particular endpoint */
    list = mcc_get_endpoint_list(*endpoint);

    if(list == null) {
        /* The endpoint does not exists (has not been registered so far),
         free the buffer and return immediately - error */
        /* Enqueue the buffer back into the free list */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);
      
        mcc_release_semaphore();
        return MCC_ERR_ENDPOINT;
    }

    /* Write the signal type into the signal queue of the particular core */
    affiliated_signal.type = BUFFER_QUEUED;
    affiliated_signal.destination = *endpoint;
    return_value = mcc_queue_signal(endpoint->core, affiliated_signal);
    if(return_value != MCC_SUCCESS) {
        /* Signal queue is full, free the buffer and return immediately - error */
        MCC_DCACHE_INVALIDATE_MLINES((void*)&bookeeping_data->free_list, sizeof(MCC_RECEIVE_LIST*));
        mcc_queue_buffer(&bookeeping_data->free_list, buf);

        mcc_release_semaphore();
        return return_value;
    }

    /* Enqueue the buffer into the endpoint buffer list */
    mcc_queue_buffer(list, buf);

    /* Semaphore-protected section end */
    mcc_release_semaphore();

    if(return_value != MCC_SUCCESS)
        return return_value;

    /* Signal the other core by generating the CPU-to-CPU interrupt */
    return_value = mcc_generate_cpu_to_cpu_interrupt();

    return return_value;
}
Example #5
0
File: Mail.c Project: gxliu/MqxSrc
void SEC_EmailAlert()
{
   MQX_TICK_STRUCT      ticks;
   MQX_XDATE_STRUCT     xdate;
   sockaddr             addr;
   _ip_address          ipaddr;
   uint_32              sock;
   uint_32              error;
   uint_32              option;
   char_ptr             event_ptr;
   char                 temp[150];
   char                 domain[30];
   char                 user[30];
    
#if DEMOCFG_AUTH_REQUIRED    
   char                 temp_encoded[40];
#endif
    

  
   if (!RTCS_resolve_ip_address(EMAIL_SERVER,&ipaddr,NULL,0)) {
      printf("Error resolving IP address for %s using DNS Server at %d.%d.%d.%d\n", EMAIL_SERVER, IPBYTES(ipcfg_get_dns_ip(BSP_DEFAULT_ENET_DEVICE, 0)));
      return;
   }
  
    /* Create socket */        
    sock = socket(AF_INET, SOCK_STREAM, 0);
    if (sock == RTCS_SOCKET_ERROR) 
    {
        printf("Error creating socket\n");
        return;
    } 

   /* Reduce buffer size of socket to save memory */
   option = SMTP_BUFFER_SIZE;   
   error = setsockopt(sock, SOL_TCP, OPT_TBSIZE, &option, sizeof(option));
   option = SMTP_BUFFER_SIZE;   
   error = setsockopt(sock, SOL_TCP, OPT_RBSIZE, &option, sizeof(option));
   option = 1000;   
   error = setsockopt(sock, SOL_TCP, OPT_TIMEWAIT_TIMEOUT, &option, sizeof(option));


    /* Allow binding to any address */
   
    #if RTCSCFG_ENABLE_IP4  
    ((sockaddr_in*)(&addr))->sin_family      = AF_INET;
    ((sockaddr_in*)(&addr))->sin_port        = 0;
    ((sockaddr_in*)(&addr))->sin_addr.s_addr = INADDR_ANY;
 
    #elif RTCSCFG_ENABLE_IP6
        printf("\nThis application don't support IPv6 only.\n");
        _task_block();
    #endif

    error = bind(sock, &addr, sizeof(addr));
    if (error != RTCS_OK) {
        printf("Error in binding socket %08x\n",error);
        shutdown(sock, FLAG_ABORT_CONNECTION);
        return;
    } 

    /* Connect to SMTP server */
    #if RTCSCFG_ENABLE_IP4
        ((sockaddr_in*)(&addr))->sin_port        = IPPORT_SMTP;
        ((sockaddr_in*)(&addr))->sin_addr.s_addr = ipaddr;
    #elif RTCSCFG_ENABLE_IP6
        printf("\nThis application does not support IPv6 only.\n");
        _task_block();
    #endif


    error = connect(sock, &addr, sizeof(addr));
    if (error != RTCS_OK) {
        printf("Error in connection %08x\n",error);
        shutdown(sock, FLAG_ABORT_CONNECTION);
        return;
    }
  
    printf("\nConnecting to SMTP server %s...\n",EMAIL_SERVER);
    printf("SMTP Server Response:\n");
    SMTP_Receive_string(sock, temp, sizeof(temp));


    /* Follow SMTP protocol to send email */   

    /* Parse domain name from the FROM address, 
     for use with the EHLO or HELO commands */
    sscanf(EMAIL_FROM,"%30s@%30s",user,domain);
  
#if DEMOCFG_AUTH_REQUIRED 
  
    /* If Authentification is required, use EHLO command */
    SMTP_Send_command(sock, "EHLO", domain, temp, sizeof(temp));
    SMTP_Send_command(sock,"AUTH LOGIN",NULL,temp,sizeof(temp));

    /* Find base64 econding of login name and send to SMTP server */
    sprintf(temp,"%s\r\n",base64_encode(AUTH_USERNAME,temp_encoded));
    SMTP_Send_string(sock,temp);
    SMTP_Receive_string(sock,temp,sizeof(temp)-1);

    /* Find base64 econding of password and send to SMTP server */
    sprintf(temp,"%s\r\n",base64_encode(AUTH_PASSWORD,temp_encoded));
    SMTP_Send_string(sock,temp);
    SMTP_Receive_string(sock,temp, sizeof(temp)-1);
#else
    /* If Authentification is not required, use HELO command as not all servers recognize EHLO */
    SMTP_Send_command(sock, "HELO", domain, temp, sizeof(temp));
#endif


   /* Transfer sender email address to server */     
   SMTP_Send_command(sock,"MAIL FROM:","<" EMAIL_FROM ">" ,temp,sizeof(temp));
   /* Transfer recipient email address to server */            
   SMTP_Send_command(sock,"RCPT TO:","<" EMAIL_TO ">" ,temp,sizeof(temp));

   /* Start DATA section */
   SMTP_Send_command(sock,"DATA",NULL,temp,sizeof(temp));

   printf("Sent:\n");
   /* Send Subject, To, and From fields */
   SMTP_Send_string(sock,(pointer)Email_header);


   /* Determine what to send as body of message */
   _time_get_ticks(&ticks);
   _time_ticks_to_xdate(&ticks,&xdate);    

   sprintf(temp, "Date: %s, %d %s %d %02d:%02d:%02d -0000\r\n\r\n",
      wday[xdate.WDAY],xdate.MDAY, months[xdate.MONTH-1],xdate.YEAR, xdate.HOUR, xdate.MIN, xdate.SEC  );
   SMTP_Send_string(sock,temp);


   /* If button pushed was the "Door"... */
   if(SEC_Params.Status==SEC_DOOR_OPEN_STATUS)
   {
      event_ptr = "Door was opened ";
   } else 
   /* If button pushed was the "Window"... */
   if(SEC_Params.Status==SEC_WINDOW_OPEN_STATUS)
   {
      event_ptr = "Window was opened ";
   }
   /* If not sure what caused stop mode to exit... */  
   else 
   {
      event_ptr = "Unknown event occurred ";
   }    
   SMTP_Send_string(sock,event_ptr);

   /* If SNTP enabled, then send exact date and time button press happened */
   #if DEMOCFG_ENABLE_SNTP
      sprintf(temp,"on %d/%d/%d at %02d:%02d:%02d GMT. \r\n",xdate.MONTH,xdate.MDAY,xdate.YEAR,xdate.HOUR,xdate.MIN,xdate.SEC);
   /* If SNTP not enabled, then give elapsed time instead */
   #else
      sprintf(temp,"%02d:%02d:%02d after system was started. \r\n",xdate.HOUR,xdate.MIN,xdate.SEC);
   #endif
   SMTP_Send_string(sock,temp);  

   if (last[0]) {
      /* Send out how long ago the last event was */
      SMTP_Send_string(sock,"Previous event was ");
      SMTP_Send_string(sock,last);
   }
   strcpy(last,temp); 
   
   /* Send Freescale signature and disconnect from server with QUIT command */
   SMTP_Send_string(sock,"\r\n-Freescale Semiconductor\r\n.\r\n");
   
   SMTP_Send_command(sock,"QUIT",NULL,temp,sizeof(temp));

  /* Close socket */
    shutdown(sock, FLAG_CLOSE_TX);  
}
Example #6
0
int_32 Shell_smtp (int_32 argc, char_ptr argv[])
{
    struct addrinfo           hints;
    struct addrinfo           *result, *rp;
    int_32                    retval = 0;
    uint_32                   sfd = 0;
    int_32                    err_code = 0;
    boolean                   print_help;
    boolean                   shorthelp = FALSE;
    SMTP_PARAM_STRUCT         params;
    char_ptr                  errstr = NULL;
    char_ptr                  server = NULL;
    char_ptr                  optstring = ":f:t:s:u:p:m:h";
    int_32                    next_option;
    char_ptr                  email_text = NULL;
    uint_32                   email_size = 0;
    MQX_TICK_STRUCT           ticks;
    MQX_XDATE_STRUCT          xdate;
    char                      date_str[DATE_LENGTH];
    
    params.login = NULL;
    params.pass = NULL;

    print_help = Shell_check_help_request(argc, argv, &shorthelp);
    
    if (print_help)
    {
        if (!shorthelp)
        {
            fprintf(stdout,"Usage:"); 
        }
        fprintf(stdout, "%s", argv[0]);
        print_usage(stdout, shorthelp);
        err_code = SHELL_EXIT_SUCCESS;
        return(err_code);
    }
    
    /* Parse command line options */
    do
    {
        next_option = Shell_getopt(argc, argv, optstring);
        switch (next_option)
        {
            case 'f':
                params.envelope.from = optarg;
                break;
            case 't':
                params.envelope.to = optarg;
                break;
            case 'm':
                params.text = optarg;
                break;
            case 's':
                server = optarg;
                break;
            case 'u':
                params.login = optarg;
                break;
            case 'p':
                params.pass = optarg;
                break;
            case 'h':
                print_usage (stdout, FALSE);
                return(SHELL_EXIT_SUCCESS);
            case '?': /* The user specified an invalid option. */
                print_usage(stderr, TRUE);
                return(SHELL_EXIT_ERROR);
            case ':': /* Option has a missing parameter. */
                printf("Option -%c requires a parameter.\n", next_option);
                return(SHELL_EXIT_ERROR);
            case -1: /* Done with options. */
                break;
            default:
                break;
        }
    }while(next_option != -1);
    
    
    _time_get_ticks(&ticks);
    _time_ticks_to_xdate(&ticks,&xdate);    

    snprintf(date_str, DATE_LENGTH, "%s, %d %s %d %02d:%02d:%02d -0000",
        wday[xdate.WDAY],xdate.MDAY, months[xdate.MONTH-1],xdate.YEAR, xdate.HOUR, xdate.MIN, xdate.SEC);
    /* Evaluate email size */
    email_size = strlen(params.envelope.from) + 
                 strlen(params.envelope.to) +
                 strlen(params.text) +
                 strlen(date_str) +
                 strlen("From: <>\r\n") +
                 strlen("To: <>\r\n") + 
                 strlen("Subject: Freescale Tower Email\r\n") +
                 strlen("Date: \r\n\r\n") +   
                 strlen("\r\n") + 1;
    /* Allocate space */
    email_text = (char_ptr) _mem_alloc_zero(email_size);
    if (email_text == NULL)
    {
        fprintf(stderr, "  Unable to allocate memory for email message.\n");
        err_code = SHELL_EXIT_ERROR;
        return(err_code);
    }
    /* Prepare email message */
    snprintf(email_text, email_size, "From: <%s>\r\n"
                                     "To: <%s>\r\n"
                                     "Subject: Freescale Tower Email\r\n"
                                     "Date: %s\r\n\r\n"
                                     "%s\r\n",
                                     params.envelope.from,
                                     params.envelope.to,
                                     date_str,
                                     params.text);
    params.text = email_text;
    
    _mem_zero(&hints, sizeof(hints));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM; /* TCP socket */
    hints.ai_flags = AI_PASSIVE;     /* For wildcard IP address */
    hints.ai_protocol = 0;           /* Any protocol */
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;

    retval = getaddrinfo(server, NULL, &hints, &result);
    if (retval != 0)
    {
        fprintf(stderr, "  getaddrinfo failed. Error: 0x%X\n", retval);
        err_code = SHELL_EXIT_ERROR;
        return(err_code);
    }
    /* Allocate buffer for error message */
    errstr = (char_ptr) _mem_alloc_system_zero(ERR_MSG_BUFF_SIZE);
    /* Try to send email using one of addresses. If it fails try another one. */
    for (rp = result; rp != NULL; rp = rp->ai_next)
    {
        _mem_copy(rp->ai_addr, &params.server, sizeof(params.server));
        /* Try to send email */
        retval = SMTP_send_email(&params, errstr, ERR_MSG_BUFF_SIZE);
        /* If connection failed try another address */
        if (retval != SMTP_ERR_CONN_FAILED)
        {
            break;
        }
    }
    /* No address succeeded */
    if (rp == NULL)
    {
        fprintf(stderr, "  Unable to connect to %s.\n", server);
        err_code = SHELL_EXIT_ERROR;
    }

    if (retval != SMTP_OK)
    {
        printf("  Email sending failed%s %s\n", (strlen(errstr) > 0) ? ":":".", errstr);
        err_code = SHELL_EXIT_ERROR;
    }
    else
    {
        printf("  Email send. Server response: %s", errstr);
    }
    /* Cleanup */
    freeaddrinfo(result);
    _mem_free(errstr);
    _mem_free(email_text);
    return(err_code);
}