Satellite Observers Workbench. NOT yet complete, just published for forum posters to \"cherry pick\" pieces of code as requiered as an example.

Dependencies:   mbed

nexstar/nexstar_old.c

Committer:
AjK
Date:
2010-10-11
Revision:
0:0a841b89d614

File content as of revision 0:0a841b89d614:

/****************************************************************************
 *    Copyright 2010 Andy Kirkham, Stellar Technologies Ltd
 *    
 *    This file is part of the Satellite Observers Workbench (SOWB).
 *
 *    SOWB is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    SOWB is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU General Public License for more details.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with SOWB.  If not, see <http://www.gnu.org/licenses/>.
 *
 *    $Id: main.cpp 5 2010-07-12 20:51:11Z ajk $
 *    
 ***************************************************************************/

#ifdef NEVERCOMPILETHIS

#include "mbed.h"
#include "nexstar.h"
#include "utils.h"
#include "debug.h"
#include "main.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

/* The main place holder data structure for the Nexstar. */
NEXSTAR_DATA nexstar;

/* A timer to look for serial comms failure. */
OneMS   timeout;

/** nexstar_process(void)
 *
 * Standard module _process function.
 */
void nexstar_process(void) {
    int i, j, q;
    signed char status, type;
    
    BLAT4;
    
    /* Multiple queued requests will start automatically after the previous
       request (see the ISR for details). However, it is possible that when
       the ISR detects the completion of a request there are, at that time,
       no more pending requests in the queue. So loop over the request queue 
       and if none are in progress, initiate a request transfer to the Nexstar. */
    if (! nexstar_request_count_status(NEXSTAR_REQUEST_IN_PROGRESS)) {
        if (nexstar_request_count_status(NEXSTAR_REQUEST_PENDING)) {
            for (i = 0, q = nexstar.currentRequest; i < NEXSTAR_NUM_OF_PACKETS; i++) {
                if (nexstar.commsPackets[q].requestStatus == NEXSTAR_REQUEST_PENDING) {
                    nexstar.currentRequest = q;
                    nexstar_send_request(q);
                    i = NEXSTAR_NUM_OF_PACKETS;
                }
                else {
                    NEXSTAR_NEXT_REQUEST(q);
                }
            }
        }
    }
    
    /* look through all the comms request packets and see if any need processing. */
    /*
    for (i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) {
        status = nexstar.commsPackets[i].requestStatus;
        type   = nexstar.commsPackets[i].requestType; 
        if (status == NEXSTAR_REQUEST_TIMEOUT) {                        
            for (j = 0; j < NEXSTAR_NUM_OF_PACKETS; j++) {
                REQUEST_SET_PACKET_STATUS(j, NEXSTAR_REQUEST_IDLE); 
                nexstar_request_packet_reset(&nexstar.commsPackets[j]);
            }
            NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED);
        }
        else if (status == NEXSTAR_REQUEST_COMPLETE) {
            switch (type) {
                case NEXSTAR_ECHO_COMMS:
                    nexstar_request_echo(NEXSTAR_PROCESS_REQUEST, i);
                    break;
                case NEXSTAR_ASK_IS_ALIGNED:
                    nexstar_request_get_aligned(NEXSTAR_PROCESS_REQUEST, i);
                    break;
                case NEXSTAR_ASK_ALTAZM_POSITION:
                    nexstar_request_get_altazm(NEXSTAR_PROCESS_REQUEST, i);
                    break;
            }
        }       
    }
    */
    
    if (nexstar.commsPackets[nexstar.currentRequest].requestStatus; == NEXSTAR_REQUEST_COMPLETE) {
        switch (type) {
            case NEXSTAR_ECHO_COMMS:
                nexstar_request_echo(NEXSTAR_PROCESS_REQUEST, nexstar.currentRequest);
                break;
            case NEXSTAR_ASK_IS_ALIGNED:
                nexstar_request_get_aligned(NEXSTAR_PROCESS_REQUEST, nexstar.currentRequest);
                break;
            case NEXSTAR_ASK_ALTAZM_POSITION:
                nexstar_request_get_altazm(NEXSTAR_PROCESS_REQUEST, nexstar.currentRequest);
                break;
        }
    }       
    
   /* If the Nexstar is in an unknown state attempt to ask it for
       alignment. Once we get a positive response we at least know
       a Nexstar is connected and responding. Until we have that
       knowledge there is little else we can do. */
    switch(nexstar.status) {
        case NEXSTAR_NOT_CONNECTED:
            if (! nexstar_request_count_request_type(NEXSTAR_ECHO_COMMS)) { 
                Uart2_flush_rxfifo();
                nexstar_request_echo(NEXSTAR_SEND_REQUEST, 0);                
            }
            return;            

        case NEXSTAR_CONNECTED:
        case NEXSTAR_NOT_ALIGNED:
            if (! nexstar_request_count_request_type(NEXSTAR_ASK_IS_ALIGNED)) {             
                Uart2_flush_rxfifo();
                nexstar_request_get_aligned(NEXSTAR_SEND_REQUEST, 0);                
            }
            return; 
            
        default:
            debug.printf("I don't know what to do! status is %d\r\n", nexstar.status);
            break;           
    }    

    /* As possible as often, request the Nexstar's pointing position. */
    if (! nexstar_request_count_request_type(NEXSTAR_ASK_ALTAZM_POSITION)) {
        nexstar_request_get_altazm(NEXSTAR_SEND_REQUEST, 0);
    }

    
}

/** nexstar_init(void)
 *
 * Standard module _init function. 
 */
void nexstar_init(void) {

    /* Setup the global mode of this Nexstar. */
    NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED);

    /* Initialise the comms packets and buffers. */
    nexstar.currentRequest = 0;
    nexstar.availableRequest = 0;
    for (int i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) {
        nexstar_request_packet_reset(&nexstar.commsPackets[i]);
        //nexstar.commsPackets[i].requestType = 0;
        //nexstar.commsPackets[i].requestStatus = NEXSTAR_REQUEST_IDLE;
        //nexstar.commsPackets[i].bufferPointer = 0;
        //nexstar.commsPackets[i].callback = NULL;
        //memset(nexstar.commsPackets[i].buffer, 0, NEXSTAR_PACKET_BUFFER_SIZE);
    }
    
    /* Prepare the one-shot timeout timers. */
    timeout.mode(ONEMS_MODE_TIMEOUT_CALLBACK);
    timeout.attach(nexstar_timeout);

    /* Initialise the UART we use. */
    Uart2_init();
}

/** nexstar_request_packet_reset
 *
 * Return a request packet back to default state.
 *
 * @param NEXSTAR_COMMS_PACKET *p A pointer to the packet to reset.
 */
void nexstar_request_packet_reset(NEXSTAR_COMMS_PACKET *p) {
    p->requestType = 0;
    p->bufferPointer = 0;
    p->callback = NULL;
    memset(p->buffer, 0, NEXSTAR_PACKET_BUFFER_SIZE);
    p->requestStatus = NEXSTAR_REQUEST_IDLE;
}

/** nexstar_p(void)
 *
 * Get a pointer to the data structure for the Nexstar.
 * Used by the API to get data.
 */
NEXSTAR_DATA * nexstar_p(void) {
    return &nexstar;
}

/** nexstar_request_count_request_type(char requestType)
 *
 * Used to find out if any of the packets are currently marked as the supplied request type.
 *
 * @param char The status to test.
 * @return bool True otherwise false
 */
int nexstar_request_count_request_type(char requestType) {
    int count, i;
    
    for (count = 0, i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) {
        if (nexstar.commsPackets[i].requestType == requestType) {
            count++;;
        }
    }    
    return count;
}

/** nexstar_request_count_status (char status)
 *
 * Used to find out if any of the packets are currently marked as the supplied status.
 *
 * @param char The status to test.
 * @return bool True otherwise false
 */
int nexstar_request_count_status(char status) {
    int count, i;
    
    for (count = 0, i = 0; i < NEXSTAR_NUM_OF_PACKETS; i++) {
        if (nexstar.commsPackets[i].requestStatus == status) {
            count++;;
        }
    }    
    return count;
}

/** nexstar_timeout(class OneMS *q)
 *
 * A callback for the timeout timer.
 *
 * @param pointer class OneMS that invoked the callback.
 */
void nexstar_timeout(class OneMS *q) {
    q->stop();  /* Ensure we stop this timer. */
    
    /* Mark this request timed out. */
    REQUEST_SET_PACKET_STATUS(nexstar.currentRequest, NEXSTAR_REQUEST_TIMEOUT);
}

/** nexstar_request_get_altazm(int mode, unsigned char handle)
 *
 * Used to either create a request to get the current AltAzm position of the Nextsra
 * or to process a previously completed request.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_get_altazm(int mode, unsigned char handle) {
    
    /* Create a request to get the ALT/AZM and queue it. */
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'Z';
        REQUEST_SET(NEXSTAR_ASK_ALTAZM_POSITION, 1);
        led3 = 1;
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(9, 0);
        nexstar.currentAltRaw = hex2bin(buffer + 5, 4);
        nexstar.currentAlt    = (double)(((double)nexstar.currentAltRaw / 65536.) * 360.);
        nexstar.currentAzmRaw = hex2bin(buffer + 0, 4);
        nexstar.currentAzm    = (double)(((double)nexstar.currentAzmRaw / 65536.) * 360.);
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        led3 = 0;
        return 1;
    }
    
    return 0;
}

/** nexstar_request_get_aligned(int mode, unsigned char handle)
 *
 * Used to either create a request to check teh Nexstar is aligned
 * or to process a previously completed request.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_get_aligned(int mode, unsigned char handle) {
    
    /* Create a request to get the ALT/AZM and queue it. */
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'J';
        nexstar.commsPackets[handle].timeout = 2000;
        REQUEST_SET(NEXSTAR_ASK_IS_ALIGNED, 1);
        led2 = 1;
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus == NEXSTAR_REQUEST_TIMEOUT) {
            NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED);
            nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
            led2 = 0;
            return 0;
        }
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(1, 0);
        NEXSTAR_SET_STATUS((buffer[0] == 1) ? NEXSTAR_ALIGNED : NEXSTAR_NOT_ALIGNED);
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        led2 = 0;
        return 1;
    }
    
    return 0;
}

/** nexstar_request_echo(int mode, unsigned char handle)
 *
 * Used to either echo a data byte off the Nexstar.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_echo(int mode, unsigned char handle) {
    
    /* Create a request to get the ALT/AZM and queue it. */
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'K';
        nexstar.commsPackets[handle].buffer[1] = 'k';
        nexstar.commsPackets[handle].timeout = 2000;
        REQUEST_SET(NEXSTAR_ECHO_COMMS, 2);
        led1 = 1;
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
    led3 = 1;
        if (nexstar.commsPackets[handle].requestStatus == NEXSTAR_REQUEST_TIMEOUT) {
            NEXSTAR_SET_STATUS(NEXSTAR_NOT_CONNECTED);
            nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
            led1 = 0;
            return 0;
        }
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(1, 0);
        if (buffer[0] == 'k') debug.printf("YES! ");
        else debug.printf("NO! ");
            
        NEXSTAR_SET_STATUS((buffer[0] == 'k') ? NEXSTAR_CONNECTED : NEXSTAR_NOT_CONNECTED);
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        led1 = 0;
        return 1;
    }
    
    return 0;
}

/** nexstar_request_set_tracking_mode(int mode, unsigned char handle, char tracking)
 *
 * Used to set the tracking mode of the Nexstar
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @param char tracking The mode to send.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_set_tracking_mode(int mode, unsigned char handle, char tracking) {

    /* Create request and queue. */    
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'T';
        nexstar.commsPackets[handle].buffer[1] = tracking;
        REQUEST_SET(NEXSTAR_SET_TRACKING, 2);
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(0, 0);
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        return 1;
    }
    
    return 0;
}

/** nexstar_request_get_tracking_mode(int mode, unsigned char handle)
 *
 * Used to find out what tracking mode Nexstar is in.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_get_tracking_mode(int mode, unsigned char handle) {

    /* Create request and queue. */    
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 't';
        REQUEST_SET(NEXSTAR_ASK_TRACKING, 1);
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(1, 0);
        nexstar.trackingMode = buffer[0];
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        return 1;
    }
    
    return 0;
}

/** nexstar_request_set_slew(int mode, unsigned char handle, double alt, double azm)
 *
 * Used to set a variable slew rate.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @param double alt The alt slew rate in degrees per second.
 * @param double azm The azm slew rate in degrees per second.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_set_slew(int mode, unsigned char handle, double alt, double azm) {
    int i;
    
    /* Create request and queue. */    
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'P';
        nexstar.commsPackets[handle].buffer[1] = '\x3';
        nexstar.commsPackets[handle].buffer[2] = '\x11';
        nexstar.commsPackets[handle].buffer[3] = alt > 0 ? '\x6' : '\x7';
        i = ((int)(alt * 3600.)) * 4;
        nexstar.commsPackets[handle].buffer[4] = (char)((i & 0xFF00) >> 8);
        nexstar.commsPackets[handle].buffer[5] = (char)(i & 0xFF);
        nexstar.commsPackets[handle].buffer[6] = '\0';
        nexstar.commsPackets[handle].buffer[7] = '\0';
        REQUEST_SET(NEXSTAR_SET_ALT_RATE, 8);
        
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'P';
        nexstar.commsPackets[handle].buffer[1] = '\x3';
        nexstar.commsPackets[handle].buffer[2] = '\x10';
        nexstar.commsPackets[handle].buffer[3] = azm > 0 ? '\x6' : '\x7';
        i = ((int)(azm * 3600.)) * 4;
        nexstar.commsPackets[handle].buffer[4] = (char)((i & 0xFF00) >> 8);
        nexstar.commsPackets[handle].buffer[5] = (char)(i & 0xFF);
        nexstar.commsPackets[handle].buffer[6] = '\0';
        nexstar.commsPackets[handle].buffer[7] = '\0';
        REQUEST_SET(NEXSTAR_SET_AZM_RATE, 8);
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(0, 0);
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        return 1;
    }
    
    return 0;
}

/** nexstar_request_set_location(int mode, unsigned char handle, NEXSTAR_LOCATION *location)
 *
 * Used to set the Nexstar's location.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @param NEXSTAR_LOCATION *location A pointer to a data struct holding the data.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_set_location(int mode, unsigned char handle, NEXSTAR_LOCATION *location) {

    /* Create request and queue. */    
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'W';
        memcpy((char *)nexstar.commsPackets[handle].buffer + 1, (char *)location, 8);
        REQUEST_SET(NEXSTAR_SET_LOCATION, 9);
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(1, 0);
        nexstar.trackingMode = buffer[0];
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        return 1;
    }
    
    return 0;
}

/** nexstar_request_set_time(int mode, unsigned char handle, NEXSTAR_TIME *time)
 *
 * Used to set the Nexstar time.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @param NEXSTAR_TIME *time A pointer to a data struct holding the data.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_set_time(int mode, unsigned char handle, NEXSTAR_TIME *time) {

    /* Create request and queue. */    
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'H';
        memcpy((char *)nexstar.commsPackets[handle].buffer + 1, (char *)time, 8);
        REQUEST_SET(NEXSTAR_SET_TIME, 9);
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(0, 0);
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        return 1;
    }
    
    return 0;
}

/** nexstar_request_get_version(int mode, unsigned char handle)
 *
 * Used to set the Nexstar software version.
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_get_version(int mode, unsigned char handle) {

    /* Create request and queue. */    
    if (mode == NEXSTAR_SEND_REQUEST) {
        REQUEST_HANDLE;
        nexstar.commsPackets[handle].buffer[0] = 'V';
        REQUEST_SET(NEXSTAR_ASK_VERSION, 1);
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        char *buffer = nexstar.commsPackets[handle].buffer;
        REQUEST_BUFFER_CHECK(2, 0);
        nexstar.version = (buffer[0] << 8) | buffer[1];
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        return 1;
    }
    
    return 0;
}

/** nexstar_request_raw(int mode, unsigned char handle, NEXSTAR_COMMS_PACKET *q)
 *
 * Used for external callers to setup a REQUEST based on an externally defined packet structure.
 *
 * This function allows other parts of the system to make Nextstar requests that are not covered
 * by the API or just want to handle a request via a callback. 
 *
 * @param int mode Determine what action to create, queue request or process packet.
 * @param unsigned char handle If processing a request this is the index of the packet to be processed.
 * @param pointer A pointer to a predefined comms request packet to copy into our queue.
 * @return zero on failure or error, non-zero otherwise.
 */
int nexstar_request_raw(int mode, unsigned char handle, NEXSTAR_COMMS_PACKET *q) {

    /* Create request and queue. */    
    if (mode == NEXSTAR_SEND_REQUEST) {
        /* Externally handled requests must have a callback defined as a completion handler. */
        if (q->callback == NULL) {
            return 0;
        }
        REQUEST_HANDLE;
        memcpy(&nexstar.commsPackets[handle], q, sizeof(NEXSTAR_COMMS_PACKET));
        REQUEST_SET(NEXSTAR_REQUEST_RAW, 0);
        return 1;
    }
    
    /* Given a completed request, parse the data and update our information. */
    if (mode == NEXSTAR_PROCESS_REQUEST) {
        if (nexstar.commsPackets[handle].requestStatus != NEXSTAR_REQUEST_COMPLETE) return 0;
        if (nexstar.commsPackets[handle].callback != NULL) {
            (nexstar.commsPackets[handle].callback)(&nexstar.commsPackets[handle]);
        }
        nexstar_request_packet_reset(&nexstar.commsPackets[handle]);            
        REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_IDLE);
        return 1;
    }
   
    return 0;
}


/** nexstar_send_request(int handle)
 *
 * Used to send a request packet to Nexstar via the serial port.
 *
 * @param int handle The packet to send.
 * @return zero on failure, non-zero otherwise. 
 */
int nexstar_send_request(int handle) {
    if (nexstar.commsPackets[handle].requestStatus == NEXSTAR_REQUEST_PENDING) {
        nexstar.commsPackets[handle].requestStatus = NEXSTAR_REQUEST_IN_PROGRESS;
        if (Uart2_puts(nexstar.commsPackets[handle].buffer, (int)nexstar.commsPackets[handle].txLength) != 0) {                
            memset(nexstar.commsPackets[handle].buffer, 0, NEXSTAR_PACKET_BUFFER_SIZE);
            nexstar.commsPackets[handle].bufferPointer = 0;
            // Note, we only start the timeout timer AFTER the TxFIFO goes empty, see below.
            return 1;
        }
        else {
            /* If we failed to fill the Tx FIFo then switch this request back to pending. */
            REQUEST_SET_PACKET_STATUS(handle, NEXSTAR_REQUEST_PENDING);        
            return 0;
        }
    }
    return 0;
}

/** UART2_IRQHandler(void)
 *
 * The interrupt service routine for the UART2.
 */
extern "C" void UART2_IRQHandler(void) {
    char c;
    uint32_t iir; 

    /* Get the interrupt identification register which also resets IIR. */
    iir = LPC_UART2->IIR;

    if (iir & 0x0001) {
        /* Eh? Then why did we interrupt? */
        return;
    }
       
    /* Do we have incoming data? */
    if (iir & UART_ISSET_RDA) {
        c = (char)LPC_UART2->RBR;
        //debug.printf(" %c", c & 0x7f);
        if (nexstar.commsPackets[nexstar.currentRequest].requestStatus != NEXSTAR_REQUEST_IN_PROGRESS) { 
            return;
        }
        nexstar.commsPackets[nexstar.currentRequest].buffer[nexstar.commsPackets[nexstar.currentRequest].bufferPointer] = c;
        nexstar.commsPackets[nexstar.currentRequest].bufferPointer++;
        nexstar.commsPackets[nexstar.currentRequest].bufferPointer &= (NEXSTAR_PACKET_BUFFER_SIZE-1);
        if (c == '#' || c == '\r' || c == '\n') {            
            timeout.stop();   /* Halt the timeout timer. */
            REQUEST_SET_PACKET_STATUS(nexstar.currentRequest, NEXSTAR_REQUEST_COMPLETE);
            
            /* Advance to the next request packet and if pending start it. */
            //NEXSTAR_NEXT_REQUEST(nexstar.currentRequest);
            //nexstar_send_request(nexstar.currentRequest);
            //debug.printf("\r\n");
        }
    }

    /* If the THRE goes empty AND the TxFIFO is also empty then a command
       was just sent to the Nexstar. Start the serial timeout timer so we 
       only make a timeout measurement AFTER we have sent our command. 
       That way we don't include our serial transmit time within the timeout
       specified by the timer. */
    if (iir & UART_ISSET_THRE) {
        if ((LPC_UART2->FIFOLVL & UART_ISSET_FIFOLVL_TXFULL) == 0) {
            timeout.start(nexstar.commsPackets[nexstar.currentRequest].timeout == 0 ? NEXSTAR_SERIAL_TIMEOUT : (uint32_t)nexstar.commsPackets[nexstar.currentRequest].timeout);
        }
    }  
    
    if (iir & UART_ISSET_RLS) {
        // Do nothing for now other than read the iir register and clear the interrupt.
    }
}

/** Uart2_init
 *
 * Initialise UART2 to our requirements for Nexstar.
 */
void Uart2_init (void) {

    /* Switch on UART2. */
    LPC_SC->PCONP |= UART2_ORMASK_PCONP;

    /* Set PCLK == CCLK, 96Mhz */
    LPC_SC->PCLKSEL1 |= UART2_ORMASK_PCLKSEL1;

    /* Enable the tx/rx to pins and select pin mode. */
    LPC_PINCON->PINSEL0  |= UART2_ORMASK_PINSEL0;
    LPC_PINCON->PINMODE0 |= UART2_ORMASK_PINMODE0;
       
    /* Set the divisor values for 9600 and then set 8,n,1 */
    LPC_UART2->LCR = UART2_SET_LCR_DLAB;
    LPC_UART2->DLL = UART2_SET_DLLSB;
    LPC_UART2->DLM = UART2_SET_DLMSB;
    LPC_UART2->LCR = UART2_SET_LCR;
    
    /* Enable FIFOs and then clear them. */
    LPC_UART2->FCR = UART2_SET_FCR;
    LPC_UART2->FCR = UART2_SET_FCR_CLEAR;

    /* Enable the RDA and THRE interrupts. */
    LPC_UART2->IER = UART2_SET_IER;
    
    /* Now it's time to do interrupts. */
    NVIC_SetVector(UART2_IRQn, (uint32_t)UART2_IRQHandler);
    NVIC_EnableIRQ(UART2_IRQn);    
}

/** Uart2_flush_rxfifo
 * 
 * Flush the input RX fifo to make sure it's empty.
 */
void Uart2_flush_rxfifo(void) {
    uint8_t c;
    while (LPC_UART2->LSR & 0x1) {
        c = LPC_UART2->RBR;
    }
}

/** Uart2_putc
 *
 * Put the character given into the TxFIFO.
 * By design there should always be room in 
 * the fifo, but check it to make sure.
 *
 * @param char The character to write.
 * @return int zero on failure, non-zero otherwise.
 */
int Uart2_putc(char c) {
    /* Check the TxFIFO is not full.  */
    if ((LPC_UART2->FIFOLVL & UART_ISSET_FIFOLVL_TXFULL) != 0) return 0;
    LPC_UART2->THR = (uint8_t)c;
    return -1;
}

/** Uart2_puts
 *
 * Put the string given into the TX FIFO.
 * By design there should always be room in 
 * the fifo, but check it to make sure.
 *
 * @param char *s Pointer The string to write.
 * @return int zero on failure, non-zero (number of chars written) otherwise.
 */
int Uart2_puts(char *s, int len) {
    int i;
    
    /* Check the FIFO is empty, as it should always be by design. */
    if ((LPC_UART2->FIFOLVL & UART_ISSET_FIFOLVL_TXFULL) == 0) {
        for (i = 0; i < len; i++) {
            LPC_UART2->THR = (uint8_t)s[i];
            debug.printf("%c", s[i]);
        }
        debug.printf("\r\n");
    }
    else {
        return 0;
    }
    return i;
}

#endif