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

Dependencies:   mbed

Revision:
0:0a841b89d614
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nexstar/nexstar_old.c	Mon Oct 11 10:34:55 2010 +0000
@@ -0,0 +1,798 @@
+/****************************************************************************
+ *    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
\ No newline at end of file