The software that runs on the Sentinel base station. This code is for the LPC1768.

Dependencies:   XBEE_900HP_SPI mbed-rtos mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /*
00002 / Sentinel software for the base station node.
00003 /
00004 / Design work done by:
00005 / Dominic Ottaviano
00006 / Sheldon Fernandes
00007 / Thien L. Nguyen
00008 */
00009 
00010 #include "mbed.h"
00011 #include "xbee900hp.h"
00012 #include "rtos.h"
00013 
00014 /*===========================================================/
00015 / Primary Configuration Area                                 /
00016 / Global Variables and Pin Assigments Declared Within        /
00017 /===========================================================*/
00018 
00019 // Serial Port Mutex to prevent multiple transmissions
00020 Mutex serial_mutex;
00021 
00022 // Declare serial output to the host PC over USB
00023 Serial pc(USBTX,USBRX);
00024 
00025 // Connected serial GPS pins
00026 Serial gps(p28,p27);
00027 
00028 // Declare pins of connected xbee module using spi (EXPERIMENTAL DRIVER)
00029 xbee900hp xbee(p11,p12,p13, p8, p9);
00030 
00031 // Led outputs on the MBED
00032 DigitalOut led1(LED1);
00033 DigitalOut led2(LED2);
00034 
00035 // Global Variables
00036 // Buffer for reading in from xbee
00037 char buffer[256];
00038 // Buffer for storing GPS data
00039 char gpsmsg[256];
00040 
00041 // Predefine threads running here
00042 // Thread to handle data inputs and outputs to the XBee
00043 void xbeeScanner(void const *args);
00044 // Thread to handle data inputs from the GPS module
00045 void hostScanner(void const *args);
00046 
00047 // Function prototypes
00048 // Function to query the GPS
00049 int getGPS(char* data);
00050 
00051 /*===========================================================/
00052 / END OF Primary Configuration Area                          /
00053 /===========================================================*/
00054 
00055 /*===========================================================/
00056 / Code to setup the watchdog timer on the MBED to handle-    /
00057 / auto resets                                                /
00058 /===========================================================*/
00059 
00060 class Watchdog
00061 {
00062 public:
00063     // Load timeout value in watchdog timer and enable
00064     void kick(float s) {
00065         LPC_WDT->WDCLKSEL = 0x1;                // Set CLK src to PCLK
00066         uint32_t clk = SystemCoreClock / 16;    // WD has a fixed /4 prescaler, PCLK default is /4
00067         LPC_WDT->WDTC = s * (float)clk;
00068         LPC_WDT->WDMOD = 0x3;                   // Enabled and Reset
00069         kick();
00070     }
00071     // "kick" or "feed" the dog - reset the watchdog timer
00072     // by writing this required bit pattern
00073     void kick() {
00074         LPC_WDT->WDFEED = 0xAA;
00075         LPC_WDT->WDFEED = 0x55;
00076     }
00077 };
00078 
00079 // Declare watchdog timer
00080 Watchdog wdt;
00081 
00082 /*===========================================================/
00083 / End of watchdog timer code                                 /
00084 /===========================================================*/
00085 
00086 /*===========================================================/
00087 / Begin main program code                                    /
00088 /===========================================================*/
00089 
00090 int main()
00091 {
00092     /*===========================/
00093     / Configuration Section      /
00094     /===========================*/
00095 
00096     // Set PC parameters
00097     // Baud rate
00098     pc.baud(57600);
00099     // Other params (8 data bits, no parity, 1 stop bit)
00100     pc.format(8,SerialBase::None,1);
00101 
00102     // Set GPS paramters
00103     // Baud rate
00104     gps.baud(4800);
00105     // Other params (8 data bits, no parity, 1 stop bit)
00106     gps.format(8,SerialBase::None,1);
00107 
00108     // Configure gps with these parameters:
00109     // NMEA, 4800 Baud, 8 Data bits, 1 Stop bit, No Parity
00110     unsigned int gpsxor = 'P'^'S'^'R'^'F'^'1'^'0'^'0'^','^'1'^','^'4'^'8'^'0'^'0'^','^'8'^','^'1'^','^'0';
00111     // Trim to 8 bits just in case
00112     gpsxor = gpsxor & 0xFF;
00113     // Send command to the GPS module
00114     gps.printf("$PSRF100,1,4800,8,1,0*%u%u\r\n",(gpsxor & 0xF0) >> 4,gpsxor & 0x0F);
00115 
00116     // Disable automatic broadcast of all messages. We are going to poll manually.
00117     gpsxor = 'P'^'S'^'R'^'F'^'1'^'0'^'3'^','^'0'^','^'0'^','^'0'^','^'1';
00118     // Trim to 8 bits just in case
00119     gpsxor = gpsxor & 0xFF;
00120     gps.printf("$PSRF103,0,0,0,1*%u%u\r\n",(gpsxor & 0xF0) >> 4,gpsxor & 0x0F);
00121 
00122     // Disable GLL
00123     gpsxor = 'P'^'S'^'R'^'F'^'1'^'0'^'3'^','^'1'^','^'0'^','^'0'^','^'1';
00124     // Trim to 8 bits just in case
00125     gpsxor = gpsxor & 0xFF;
00126     gps.printf("$PSRF103,1,0,0,1*%u%u\r\n",(gpsxor & 0xF0) >> 4,gpsxor & 0x0F);
00127 
00128     // Disable GSA
00129     gpsxor = 'P'^'S'^'R'^'F'^'1'^'0'^'3'^','^'2'^','^'0'^','^'0'^','^'1';
00130     // Trim to 8 bits just in case
00131     gpsxor = gpsxor & 0xFF;
00132     gps.printf("$PSRF103,2,0,0,1*%u%u\r\n",(gpsxor & 0xF0) >> 4,gpsxor & 0x0F);
00133 
00134     // Disable GSV
00135     gpsxor = 'P'^'S'^'R'^'F'^'1'^'0'^'3'^','^'3'^','^'0'^','^'0'^','^'1';
00136     // Trim to 8 bits just in case
00137     gpsxor = gpsxor & 0xFF;
00138     gps.printf("$PSRF103,3,0,0,1*%u%u\r\n",(gpsxor & 0xF0) >> 4,gpsxor & 0x0F);
00139 
00140     // Disable RMC
00141     gpsxor = 'P'^'S'^'R'^'F'^'1'^'0'^'3'^','^'4'^','^'0'^','^'0'^','^'1';
00142     // Trim to 8 bits just in case
00143     gpsxor = gpsxor & 0xFF;
00144     gps.printf("$PSRF103,4,0,0,1*%u%u\r\n",(gpsxor & 0xF0) >> 4,gpsxor & 0x0F);
00145 
00146     // Disable VTG
00147     gpsxor = 'P'^'S'^'R'^'F'^'1'^'0'^'3'^','^'5'^','^'0'^','^'0'^','^'1';
00148     // Trim to 8 bits just in case
00149     gpsxor = gpsxor & 0xFF;
00150     gps.printf("$PSRF103,5,0,0,1*%u%u\r\n",(gpsxor & 0xF0) >> 4,gpsxor & 0x0F);
00151 
00152     // Enable watchdog with a reasonable half second timeout
00153     wdt.kick(1000);
00154 
00155     /*===========================/
00156     / END Configuration Section  /
00157     /===========================*/
00158     
00159 
00160     while (true) {
00161         // Define Keys
00162         char startkey[12] = "SentinelOn";
00163         char endkey[13] = "SentinelOff";
00164         char cmdbuff[30];
00165 
00166         // LED 1 on shows ready status.
00167         led1 = 1;
00168         // Start loop waiting for start message
00169         do {
00170             if (pc.readable() == true) {
00171                 // Get bytes from computer
00172                 pc.scanf("%s",cmdbuff);
00173             }
00174             wdt.kick();
00175         } while (strcmp( startkey, cmdbuff ) != 0);
00176         // Clear string in buffer
00177         cmdbuff[0] = '\0';
00178         // LED 1 off as we enter next segment
00179         led1 = 0;
00180 
00181         // Let host know that we are starting.
00182         pc.printf("SLON\r\n");
00183 
00184         xbee.clearBuff();
00185 
00186         // Start xbeeScanner Thread
00187         Thread xbscan(xbeeScanner);
00188         Thread hostscan(hostScanner);
00189 
00190         // Main runloop
00191         led2 = 1;
00192         do {
00193             serial_mutex.lock();
00194             if (pc.readable() == true) {
00195                 // Get bytes from computer
00196                 pc.scanf("%s",cmdbuff);
00197             }
00198             serial_mutex.unlock();
00199             wdt.kick();
00200         } while (strcmp( endkey, cmdbuff ) != 0);
00201         led2 = 0;
00202 
00203         // Clear string in buffer
00204         cmdbuff[0] = '\0';
00205 
00206         xbscan.terminate();
00207         hostscan.terminate();
00208     }
00209 }
00210 
00211 // Thread to update host position
00212 void hostScanner(void const *args)
00213 {
00214     // Set variables, there are more than we need here but it would be useful in the future if we did need any.
00215     char nodeid[5] = "BASE";
00216     char ns, ew;
00217     int lock;
00218     double satsused;
00219     double hdop;
00220     double latitude, longitude;
00221     double altitude;
00222     double time;
00223     char altunits;
00224     double geoidsep;
00225     char geoidunits;
00226     int difrefstationid;
00227     unsigned int gpschecksum;
00228     
00229     serial_mutex.lock();
00230     // Announce base node to computer application
00231     pc.printf("ANCE,%s,\r\n",nodeid);
00232     serial_mutex.unlock();
00233 
00234     // Main run loop
00235     while (true) {
00236         // Get new data from the GPS and if data is read successfully continue
00237         if (!(getGPS(gpsmsg))) {
00238             // Parse the recieved data and check if its valid (HINT: lf = double since pointers aren't promoted)
00239             if(sscanf(gpsmsg, "$GPGGA,%lf,%lf,%c,%lf,%c,%i,%lf,%lf,%lf,%c,%lf,%c,,%i*%x", &time, &latitude, &ns, &longitude, &ew, &lock, &satsused, &hdop, &altitude, &altunits, &geoidsep, &geoidunits, &difrefstationid, &gpschecksum) == 14) {
00240                 // Check if the lock is valid
00241                 if((lock != 1) && (lock != 2) && (lock != 6)) {
00242                     // Lock is not valid, let host know.
00243                     serial_mutex.lock();
00244                     pc.printf("DNLK,%s,NOLOCK\r\n",nodeid);
00245                     serial_mutex.unlock();
00246                 } else {
00247                     // Convert latitude into proper form for display on a map.
00248                     double degrees;
00249                     double minutes = modf(latitude/100.0f, &degrees);
00250                     minutes = (minutes*100.0f)/60.0f;
00251                     latitude = degrees + minutes;
00252                     // Convert longitude
00253                     minutes = modf(longitude/100.0f, &degrees);
00254                     minutes = (minutes*100.0f)/60.0f;
00255                     longitude = degrees + minutes;
00256 
00257                     // Correct for south and west.
00258                     if(ns == 'S') {
00259                         latitude  *= -1.0;
00260                     }
00261                     if(ew == 'W') {
00262                         longitude *= -1.0;
00263                     }
00264                     
00265                     serial_mutex.lock();
00266                     // Send formatted info to the host
00267                     pc.printf("DLIN,%s,%f,%f,%f,%f,\r\n",nodeid, latitude, longitude, altitude, satsused);
00268                     serial_mutex.unlock();
00269                 }
00270                 // Wait a second for GPS data to be fresh again and not waste cycles.
00271                 Thread::wait(1000);
00272             } else {
00273                 // GPS hasn't found a good enough lock
00274                 serial_mutex.lock();
00275                 pc.printf("DNLK,%s,NOLOCK\r\n",nodeid);
00276                 serial_mutex.unlock();
00277                 // If this check fails we give up cpu time to another thread but only momentarily, we need to get this data successfully.
00278                 Thread::wait(500);
00279             }
00280         } else {
00281             // GPS hasn't found lock or sent a corrupted message
00282             serial_mutex.lock();
00283             pc.printf("DNLK,%s,NOLOCK\r\n",nodeid);
00284             serial_mutex.unlock();
00285             // If this check fails we give up cpu time to another thread but only momentarily, we need to get this data successfully.
00286             Thread::wait(500);
00287         }
00288     }
00289 }
00290 
00291 // Thread to scan the xbee
00292 void xbeeScanner(void const *args)
00293 {
00294     // Main runloop
00295     while (true) {
00296         // check if xbee is flagging data to be read
00297         while(xbee.attn() == 0) {
00298             // Read in data and run all background checksum and validation stuff
00299             if (xbee.readPacket(buffer) == 0) {
00300                 serial_mutex.lock();
00301                 pc.printf("%s\r\n", buffer);
00302                 serial_mutex.unlock();
00303             } else {
00304                 serial_mutex.lock();
00305                 pc.printf("Packet Failed Validation\r\n");
00306                 serial_mutex.unlock();
00307                 xbee.clearBuff();
00308             }
00309         }
00310         // Give up rest of timeslice to boost that performance
00311         Thread::yield();
00312     }
00313 }
00314 
00315 // Function to get the gps message and make sure its valid.
00316 int getGPS(char* data)
00317 {
00318     // Request a query of GGA
00319     // Precomputed checksum to save cpu cycles
00320     serial_mutex.lock();
00321     gps.printf("$PSRF103,0,1,0,1*%u%u\r\n",0x2,0x5);
00322     serial_mutex.unlock();
00323 
00324     // Timer to prevent hangs if gps doesn't respond.
00325     Timer gpsTO;
00326     gpsTO.start();
00327 
00328     // Wait for gps to becom readable.
00329     while (gps.readable() == false) {
00330         // Timeout
00331         if (gpsTO.read() > 2) {
00332             return 1;
00333         }
00334     }
00335 
00336     // Wait a tiny bit to allow the gps to send the whole line.
00337     Thread::wait(50);
00338     // Get data from gps
00339     serial_mutex.lock();
00340     gps.scanf("%s",data);
00341     serial_mutex.unlock();
00342 
00343     // Compute checksum of recieved gps data
00344     int i = 0;
00345     unsigned int calcgpschecksum = 0;
00346     // Checksum is calculated between and not including the $ and *
00347     while ((data[i] != '\0') && (data[i] != '*')) {
00348         // Skip the $
00349         if (data[i] != '$') {
00350             calcgpschecksum = calcgpschecksum ^ data[i];
00351         }
00352         i++;
00353     }
00354     // Shift the checksum to match the format we recieve from the gps
00355     calcgpschecksum = calcgpschecksum & 0xFF;
00356 
00357     // Get checksum sent by gps out of string
00358     unsigned int realgpschecksum = 0;
00359     char checksumarray[3];
00360     for (int i = 0; i < 256; i++) {
00361         if (data[i] == '*') {
00362             // Create little array with ascii hex values.
00363             checksumarray[0] = data[i+1];
00364             checksumarray[1] = data[i+2];
00365             checksumarray[2] = '\0';
00366             // Convert ascii values to regular integer
00367             sscanf(checksumarray,"%x",&realgpschecksum);
00368             break;
00369         }
00370     }
00371 
00372     // Check for checksum match
00373     if( calcgpschecksum == realgpschecksum ) {
00374         return 0;
00375     }
00376 
00377     // No checksum match
00378     return 1;
00379 }