[Firebug-cvs] firebug/web gps_driver.html,1.6,1.7
Brought to you by:
doolin
From: <cs...@us...> - 2003-07-29 17:58:50
|
Update of /cvsroot/firebug/firebug/web In directory sc8-pr-cvs1:/tmp/cvs-serv25646 Modified Files: gps_driver.html Log Message: gps page updated for Leadtek Index: gps_driver.html =================================================================== RCS file: /cvsroot/firebug/firebug/web/gps_driver.html,v retrieving revision 1.6 retrieving revision 1.7 diff -C2 -d -r1.6 -r1.7 *** gps_driver.html 9 Jun 2003 17:53:18 -0000 1.6 --- gps_driver.html 29 Jul 2003 17:54:28 -0000 1.7 *************** *** 12,229 **** <meta name="author" content="Carmel Majidi, UC Berkeley" /=""> </head> ! <body> <h1>FireBug --- GPS Driver</h1> ! <p> FireBug uses the <tt>gps</tt> driver to interface with a GPS receiver ! and handle location information. </p> <h2>Introduction</h2> ! <p> The current driver implements standard NMEA protocol to interact ! with an AXIOM GPS receiver. Running <tt>gpsM.nc</tt> on ! the client mote initializes the receiver for GPS Fix Data (GGA) ! reception. Incoming GGA data is checked by the client for validity, ! parsed, and then stored in its EEPROM flash memory. </p> ! <h2>How <tt>gps</tt> works</h2> ! <p> GPS receivers provide location and time information in a variety ! of data formats. At initialization, the client's UART is ! set to the same baud rate as the GPS receiver. Next, <tt>clearGPS()</tt> ! is called, which commands the receiver to block all output. ! The receiver requires several seconds before it can start processing ! NMEA commands following power on. For this reason, the first command ! in <tt>clearGPS()</tt> is sent 100 times until the receiver has ! warmed up.</p> ! <p>For this application, a single GGA message is required. To acquire this, ! <tt>getGPS()</tt> is called, which requests GGA data at 1 Hz. ! The number of satellites used in constructing each GGA message ! is then determined. When this number exceeds three, the corresponding ! message is parsed and stored in the client's EEPROM.</p> ! <p> Values stored in the client's memory can the be retrieved and broadcasted ! over the radio at any time with <tt>GenericBase</tt>. Instructions ! on this are given at the end of this guide. </p> ! <h2>Sending Commands to the Receiver</h2> ! <p> Communication between the client and receiver is handled by <tt> ! gpsM.nc</tt>. After the client's second UART ! (UART1) is set to 4800 baud, NMEA commands may be sent to the ! gps receiver. For SiRF chips, these generally have the form:</p> ! <center> ! <p>$PSRF,103,<b>Message type</b>,00,<b>Rate</b>,01,*<b>Checksum</b></p> ! </center> ! <p>followed by a carriage return ('\r') and linefeed ('\n'). There are six ! message types: </p> ! <center> ! <p>GGA=00, GLL=01, GSA=02, GSV=03, RMC=04, VTG=05</p> ! </center> ! <p> To block output of a certain message type, set Rate = 00. Rate = 01 corresponds ! to a 1 Hz output. Finally, the checksum is computed by performing an XOR ! on all characters, including the comma delimiters, between $ and *. Each ! character of the above string is contained as an element in the array <tt> ! cmd_msg</tt>, which is used throughout <tt>gpsM.nc</tt>. By changing ! array entries, different commands can be sent to the receiver, as shown ! below:</p> ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"><b>gpsM.nc</b> ! <pre> command result_t StdControl.start() {<br><br> j = 0;<br><br> cmd_msg[j++] = '$';<br> cmd_msg[j++] = 'P';<br> cmd_msg[j++] = 'S';<br> cmd_msg[j++] = 'R';<br> cmd_msg[j++] = 'F';<br> cmd_msg[j++] = '1';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '3';<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> j++;<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = ',';<br> cmd_msg[j++] = '0';<br> cmd_msg[j++] = '1';<br> cmd_msg[j++] = '*';<br> cmd_msg[j++] = '2';<br> j++;<br> cmd_msg[j++] = '\r';<br> cmd_msg[j++] = '\n';<br> cmd_msg[j++] = 0x00;<br><br> call clearGPS();<br> call getGPS();<br> return call SubControl.start();<br> }<br><br> command result_t clearGPS() { <br> ...<br> // Clear GLL<br> cmd_msg[10] = '1';<br> cmd_msg[22] = '5';<br> for (i = 0; i < j; i++){<br> loop_until_bit_is_set(UCSR1A, UDRE);<br> outb(UDR1,cmd_msg[i]);<br> }<br> ...<br> }<br><br> command result_t getGPS() { <br> ...<br> // Request GGA data at 1 Hz<br> cmd_msg[10] = '0';<br> cmd_msg[16] = '1';<br> cmd_msg[22] = '5';<br> for (i = 0; i < j; i++){<br> loop_until_bit_is_set(UCSR1A, UDRE);<br> outb(UDR1,cmd_msg[i]);<br> }<br> ...<br> }<br></pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <p>Here, the command outb(UDR1,cmd_msg[i]) sends the byte at entry <i>i</i> ! of <tt>cmd_msg</tt> out to UART1. </p> ! <h2>Receiving Data from GPS Module</h2> ! <p>Data enters into the client from the receiver via UART1. Messages from ! the receiver are collected byte by byte with the command <tt>inp(UDR1)</tt> ! and temporarily stored in an array, <tt>rxBuffer</tt> ! . Data is collected only after the GGA start sequence, <tt>$GPGGA</tt> ! , is completed. Collection stops when the * delimiter is reached, ! after which point, the 40th and 41st entries of the buffer are combined ! to determine the number of satellites, i.e.</p> ! <center> ! <p>num_satellites = 10*(rxBuffer[40] - '0') + (rxBuffer[41] - '0');</p> ! </center> ! <p>If <tt>num_satellite</tt> < 4, <tt>rxBuffer</tt> is cleared and the ! client waits again for the GGA start sequence to pass in the subsequent ! message until it resumes data collection. Otherwise, the data stored ! in the buffer is parsed and stored in EEPRROM using <tt>logGPS</tt> ! .</p> ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"> ! <pre> command result_t getGPS() {<br> ... <br> while(num_satellites < 4) {<br> k = 0;<br> incoming = TRUE;<br> call waitGPS();<br> while(incoming) {<br> if (inp(UCSR1A) & (1 << RXC)){<br> data = inp(UDR1);<br> if (data == '*') {<br> incoming = FALSE;<br> }<br> rxBuffer[k++] = data;<br> }<br> }<br> num_satellites = 10*(rxBuffer[40] - '0') + (rxBuffer[41] - '0'); <br> }<br><br> // Parse and store input<br> call logGPS(rxBuffer);<br> return SUCCESS;<br> }<br><br> command result_t waitGPS() {<br> uint8_t last[3]; // array of last 3 characters from GPS <br> bool waiting = TRUE;<br> <br> while(waiting) {<br> last[3] = last[2];<br> last[2] = last[1];<br> if (inp(UCSR1A) & (1 << RXC)) {<br> last[1] = inp(UDR1);<br> }<br> if(last[3]=='G') {<br> if(last[2]=='G') {<br> if(last[1]=='A') {<br> waiting = FALSE;<br> }<br> }<br> }<br> }<br> return SUCCESS;<br> }<br></pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <h2>Logging and Retrieving Data</h2> ! <p>Fields in the GGA message are comma delimited. These are parsed with ! <tt> logGPS()</tt>, which simultaneously stores the data into the ! client's EEPROM using <tt>LoggerWrite.write</tt>. One line of memory ! is reserved for each field, and these are numbered as follows:<br> ! <br> ! </p> ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td valign="Top"><b>Field</b><br> ! </td> ! <td valign="Top"><b>Line #<br> ! </b></td> ! <td valign="Top"><b>Field<br> ! </b></td> ! <td valign="Top"><b>Line #</b><br> ! </td> ! </tr> ! <tr> ! <td valign="Top">UTC Position<br> ! </td> ! <td valign="Top">25<br> ! </td> ! <td valign="Top">HDOP<br> ! </td> ! <td valign="Top">32<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Latitude<br> ! </td> ! <td valign="Top">26<br> ! </td> ! <td valign="Top">MSL Altitude<br> ! </td> ! <td valign="Top">33<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">N/S Indicator<br> ! </td> ! <td valign="Top">27<br> ! </td> ! <td valign="Top">Altitude Units<br> ! </td> ! <td valign="Top">34<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Longitude<br> ! </td> ! <td valign="Top">28<br> ! </td> ! <td valign="Top">Geoid Separation<br> ! </td> ! <td valign="Top">35<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">E/W Indicator<br> ! </td> ! <td valign="Top">29<br> ! </td> ! <td valign="Top">Separation Units<br> ! </td> ! <td valign="Top">36<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Position Fix Indicator<br> ! </td> ! <td valign="Top">30<br> ! </td> ! <td valign="Top">Age of DGPS Correlation<br> ! </td> ! <td valign="Top">37<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Satellites Used<br> ! </td> ! <td valign="Top">31<br> ! </td> ! <td valign="Top">DGPS Reference Station ID<br> ! </td> ! <td valign="Top">39<br> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! <p> To retrieve data, load a second mote with <code>GenericBase</code> and ! perform the following: </p> ! <ol> ! <li>Leaving the GenericBase mote connected to the programming board, ! start the serial port forwarding service using the command ! <code>java net.tinyos.sf.SerialForward</code></li> ! <li>Broadcast retrieve command over the radio: <code>java net.tinyos.tools.gpsBcast ! <group ID> <b>Field Name</b> <gps ! mote ID></code></li> ! <li>Packet is sent to the base station via radio. Contained in the packet ! payload is the data for the selected field. </li> ! </ol> ! <h2>Instructions for Use</h2> ! <p>NOTE: gps.nc only runs on the mica2 platform</p> ! <ol> ! <li>Load gps into mica2</li> ! <li>Mica2 will take several minutes to lock on to satellites</li> ! <li>Load a second mote with GenericBase</li> ! <li>Leaving the GenericBase mote connected to the programming board, ! start the serial port forwarding service using the command <br> ! <center><code>java net.tinyos.sf.SerialForward</code></center> ! </li> ! <li>Run gpsBcast to have gps data sent to the GenericBase mote (base station) ! over the radio. From the <tt>firebug/project/java</tt> directory, type ! <br> ! <center><code>./gpsrun.sh <group ID> <b>Field Name</b> ! <gps mote ID></code></center> ! </li> ! <li>Packet is sent to the base station via radio. Contained in the packet ! payload is the data for the selected field.</li> ! </ol> ! Alternatively, the gps driver can be connected directly to the PC via ! the programming board. GPS data could be sent to UART and displayed ! on the PC with a java application. .<br> <h2>Useful Links</h2> <p><a href="http://nmviewogc.cr.usgs.gov/viewer.htm">USGS National Map Viewer</a> --- 12,217 ---- <meta name="author" content="Carmel Majidi, UC Berkeley" /=""> </head> ! ! <body> ! <h1>FireBug --- GPS Driver</h1> ! <p>FireBug uses the <tt>gps</tt> driver to interface with a GPS ! receiver and handle location information.</p> ! <h2>Introduction</h2> ! <p>The current driver implements standard NMEA protocol to interact ! with an Leadtek GPS receiver. The incoming GPS data stream is ! filtered for GGA messages, which are compressed into an 11-byte ! character array and stored in the host's EEPROM memory.</p> ! ! <h2>Receiving a GGA Message</h2> ! <p>GPS receivers provide location and time information in a variety ! of data formats. For this application, the GGA message contains ! all the necessary time and geographic information and hence is the ! only one used. Each GPS message starts with <tt>$GP</tt> followed ! by the message identifier (MID). Data streaming in from the receiver ! is continuously monitored so that when the MID sequence for GGA is ! received, the preceding message is stored in a buffer, <tt>gga_string ! </tt>.</p> ! ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"> ! <pre> ! event TOS_MsgPtr GpsReceive.receive(TOS_MsgPtr data) {<br> int8_t gga_string[MSG_LENGTH];<br> bool gga_read = FALSE;<br> bool gga_read_done = FALSE;<br> uint16_t i = 0;<br> uint8_t j = 0;<br> <br> GPS_MsgPtr gps_data = (GPS_MsgPtr)data;<br> <br> while (!gga_read_done) {<br> <br> if(gps_data->data[i] == 'G') {<br> if(gps_data->data[i+1] == 'G') {<br> if(gps_data->data[i+2] == 'A') {<br> gga_read = TRUE;<br> }<br> }<br> }<br> ...<br> if(gga_read) {<br> gga_string[j] = gps_data->data[i];<br> j++;<br> }<br> <br> i++;<br> }<br> } ! </pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! ! <p>Recording is completed with arrival of the termination byte, ! <tt>*</tt>. <tt>gga_string</tt>, is then sent to <tt>parseGGA</tt>, ! where it is broken into an array of character strings for log entry. ! ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"> ! <pre> ! event TOS_MsgPtr GpsReceive.receive(TOS_MsgPtr data) {<br> ...<br> while (!gga_read_done) {<br> ...<br> if(gps_data->data[i] == '*') {<br> if(gga_read) {<br> call <b>parseGPS</b>(gga_string, j);<br> gga_read = FALSE;<br> gga_read_done = TRUE;<br> }<br> }<br> ...<br> }<br> } ! </pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! ! <h2>Storing GGA data</h2> ! <p>In <tt>parseGGA</tt>, the comma-delimited fields of <tt>gga_string ! </tt> are placed into an array, <tt>write</tt>, which is then sent to ! <tt>logGPS</tt> for storage.</p> ! ! <p>The process for compressing field information to one or two bytes ! is described below. First, a pointer to a <tt>GGA_Msg</tt> is set. ! A <tt>GGA_Msg</tt> has the following data structure:</p> ! ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"> ! <b>gps.h</b> ! <pre> ! typedef struct GGA_Msg<br> {<br> uint8_t hours;<br> uint8_t minutes;<br> uint16_t dec_sec;<br> uint8_t Lat_deg;<br> uint16_t Lat_dec_min;<br> uint8_t Long_deg;<br> uint16_t Long_dec_min;<br> uint8_t NSEWind;<br> } GGA_Msg; ! </pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! ! <p>The entry <tt>write[i][j]</tt> represents the ith character in the ! jth field of GGA string. Fields of interest, their field number, and ! the number of characters they contain, including decimal points, are ! given in the table below:</p> ! ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td valign="Top"><b> Field </b><br> ! </td> ! <td valign="Top"><b> Field # <br> ! </b></td> ! <td valign="Top"><b> # of Characters <br> ! </b></td> ! </tr> ! <tr> ! <td valign="Top">MID<br> ! </td> ! <td valign="Top">0<br> ! </td> ! <td valign="Top">3<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">UTC<br> ! </td> ! <td valign="Top">1<br> ! </td> ! <td valign="Top">10<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Latitude<br> ! </td> ! <td valign="Top">2<br> ! </td> ! <td valign="Top">8<br> ! </td> ! </tr> ! <tr> ! <td valign="Top"> N/S Indicator <br> ! </td> ! <td valign="Top">3<br> ! </td> ! <td valign="Top">1<br> ! </td> ! </tr> ! <tr> ! <td valign="Top">Longitude<br> ! </td> ! <td valign="Top">4<br> ! </td> ! <td valign="Top">9<br> ! </td> ! </tr> ! <tr> ! <td valign="Top"> E/W Indicator <br> ! </td> ! <td valign="Top">5<br> ! </td> ! <td valign="Top">1<br> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! ! <p>Characters representing numbers in ASCII are converted to integers ! by the operation <tt>write[i][j]-'0'</tt>. So for example, the UTC ! hour, which is given by the first two characters of the second field ! of <tt>write</tt>, is stored as a single 8-bit integer in the line</p> ! ! <center>pGGA->hours = 10*(write[1][0]-'0') + (write[1][1]-'0');</center> ! ! <p>The rest of <tt>GGA_Str</tt> is likewise assembled in this manner.</p> ! ! <center> ! <table class="code"> ! <tbody> ! <tr> ! <td width="100%"> ! <pre> ! pGGA->minutes = 10*(write[1][2]-'0') + (write[1][3]-'0'); ! pGGA->dec_sec = 10000*(write[1][4]-'0') + 1000*(write[1][5]-'0') ! + 100*(write[1][7]-'0') + 10*(write[1][8]-'0') ! + (write[1][9]-'0'); ! ! pGGA->Lat_deg = 10*(write[2][0]-'0') + (write[2][1]-'0'); ! pGGA->Lat_dec_min = 100000*(write[2][2]-'0') + 10000*(write[2][3]-'0') ! + 1000*(write[2][4]-'0') + 100*(write[2][5]-'0') ! + 10*(write[2][6]-'0') + (write[2][7]-'0'); ! ! pGGA->Long_deg = 100*(write[4][0]-'0') + 10*(write[4][1]-'0') + (write[4][2]-'0'); ! pGGA->Long_dec_min = 100000*(write[4][3]-'0') + 10000*(write[4][4]-'0') ! + 1000*(write[4][5]-'0') + 100*(write[4][6]-'0') ! + 10*(write[4][7]-'0') + (write[4][8]-'0'); ! ! NS = (write[3][0] == 'N') ? 1 : 0; ! EW = (write[5][0] == 'W') ? 1 : 0; ! pGGA->NSEWind = EW | (NS<<4); // eg. Status = 000N000E = 00010000 ! </pre> ! </td> ! </tr> ! </tbody> ! </table> ! </center> ! ! <p>For storage into EEPROM, <tt>GGA_Str</tt> data is entered into character ! array, <tt>log_array</tt>. For 16-bit data, the 8 most significant bits ! precede the 8 least significant bits as shown for Latitude decimal seconds:</p> ! <tt><p>log_array[5] = (pGGA->Lat_dec_min)>>8;<br> ! log_array[6] = pGGA->Lat_dec_min;</p></tt> ! ! <p>Lastly, <tt>log_array</tt> is written into line 25 of EEPROM with the command ! <tt>call LoggerWrite.write(0x19,(char *)log_array))</tt></p> ! ! <hr /=""> ! ! <h2>Click <a href="gps_tests.htm">here</a> for experimental results</h2> ! ! <hr /=""> ! <h2>Useful Links</h2> <p><a href="http://nmviewogc.cr.usgs.gov/viewer.htm">USGS National Map Viewer</a> |