oncore-shmem.html revision 280849
1132451Sroberto<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 2132451Sroberto 3132451Sroberto<html> 4132451Sroberto 5182007Sroberto <head> 6182007Sroberto <meta http-equiv="content-type" content="text/html;charset=iso-8859-1"> 7182007Sroberto <title>ONCORE - SHMEM</title> 8182007Sroberto <link href="scripts/style.css" type="text/css" rel="stylesheet"> 9182007Sroberto </head> 10132451Sroberto 11182007Sroberto <body> 12182007Sroberto <h3>Motorola ONCORE - The Shared Memory Interface</h3> 13280849Scy<p>Last update: 14280849Scy <!-- #BeginDate format:En2m -->21-Oct-2010 23:44<!-- #EndDate --> 15280849Scy UTC</p> 16182007Sroberto <hr> 17182007Sroberto <h4>Introduction</h4> 18182007Sroberto <p>In NMEA mode, the Oncore GPS receiver provides the user with the same information as other GPS receivers. In BINARY mode, it can provide a lot of additional information.</p> 19182007Sroberto <p>In particular, you can ask for satellite positions, satellite health, signal levels, the ephemeris and the almanac, and you can set many operational parameters. In the case of the VP, you can get the pseudorange corrections necessary to act as a DGPS base station, and you can see the raw satellite data messages themselves.</p> 20182007Sroberto <p>When using the Oncore GPS receiver with NTP, this additional information is usually not available since the receiver is only talking to the oncore driver in NTPD. To make this information available for use in other programs, (say graphic displays of satellites positions, plots of SA, etc.), a shared memory interface (SHMEM) has been added to the refclock_oncore driver on those operating systems that support shared memory.</p> 21182007Sroberto <p>To make use of this information you will need an Oncore Reference Manual for the Oncore GPS receiver that you have. The Manual for the VP only exists as a paper document, the UT+/GT+/M12 manuals are available as a pdf documents at <a href="http://www.synergy-gps.com/Mot_Manuals.html">Synergy</a> .</p> 22182007Sroberto <p>This interface was written by Poul-Henning Kamp (phk@FreeBSD.org), and modified by Reg Clemens (reg@dwf.com). The interface is known to work in FreeBSD, Linux, and Solaris.</p> 23182007Sroberto <h4>Activating the Interface</h4> 24182007Sroberto <p>Although the Shared Memory Interface will be compiled into the Oncore driver on those systems where Shared Memory is supported, to activate this interface you must include a <b>STATUS</b> or <b>SHMEM</b> line in the <tt>/etc/ntp.oncore</tt> data file that looks like</p> 25182007Sroberto <pre> 26132451Sroberto STATUS < file_name ><br> 27182007Sroberto 28132451Sroberto or<br> 29182007Sroberto 30132451Sroberto SHMEM < file_name > 31132451Sroberto</pre> 32182007Sroberto Thus a line like 33182007Sroberto <pre> 34132451Sroberto SHMEM /var/adm/ntpstats/ONCORE 35132451Sroberto</pre> 36182007Sroberto <p>would be acceptable. This file name will be used to access the Shared Memory.</p> 37182007Sroberto <p>In addition, one the two keywords <b>Posn2D</b> and <b>Posn3D</b> can be added to see @@Ea records containing the 2D or 3D position of the station (see below). Thus to activate the interface, and see 3D positions, something like</p> 38182007Sroberto <pre> 39132451Sroberto SHMEM /var/adm/ntpstats/ONCORE 40132451Sroberto Posn3D 41132451Sroberto</pre> 42182007Sroberto <p>would be required.</p> 43182007Sroberto <h4>Storage of Messages in Shared Memory</h4> 44182007Sroberto <p>With the shared memory interface, the oncore driver (refclock_oncore) allocates space for all of the messages that it is configured to receive, and then puts each message in the appropriate slot in shared memory as it arrives from the receiver. Since there is no easy way for a client program to know when the shared memory has been updated, a sequence number is associated with each message, and is incremented when a new message arrives. With the sequence number it is easy to check through the shared memory segment for messages that have changed.</p> 45182007Sroberto <p>The Oncore binary messages are kept in their full length, as described in the Reference manual, that is everything from the @@ prefix thru the <checksum><CR><LF>.</p> 46182007Sroberto <p>The data starts at location ONE of SHMEM (NOT location ZERO).</p> 47182007Sroberto <p>The messages are stacked in a series of variable length structures, that look like</p> 48182007Sroberto <pre> 49132451Sroberto struct message { 50132451Sroberto u_int length; 51132451Sroberto u_char sequence; 52132451Sroberto u_char message[length]; 53132451Sroberto } 54132451Sroberto</pre> 55182007Sroberto <p>if something like that were legal. That is, there are two bytes (caution, these may NOT be aligned with word boundaries, so the field needs to be treated as a pair of u_char), that contains the length of the next message. This is followed by a u_char sequence number, that is incremented whenever a new message of this type is received. This is followed by 'length' characters of the actual message.</p> 56182007Sroberto <p>The next structure starts immediately following the last char of the previous message (no alignment). Thus, each structure starts a distance of 'length+3' from the previous structure.</p> 57182007Sroberto <p>Following the last structure, is a u_int containing a zero length to indicate the end of the data.</p> 58182007Sroberto <p>The messages are recognized by reading the headers in the data itself, viz @@Ea or whatever.</p> 59182007Sroberto <p>There are two special cases.</p> 60182007Sroberto <p>(1) The almanac takes a total of 34 submessages all starting with @@Cb.<br> 61182007Sroberto 35 slots are allocated in shared memory. Each @@Cb message is initially placed in the first of these locations, and then later it is moved to the appropriate location for that submessage. The submessages can be distinguished by the first two characters following the @@Cb header, and new data is received only when the almanac changes.</p> 62182007Sroberto <p>(2) The @@Ea message contains the calculated location of the antenna, and is received once per second. However, when in timekeeping mode, the receiver is normally put in 0D mode, with the position fixed, to get better accuracy. In 0D mode no position is calculated.</p> 63182007Sroberto <p>When the SHMEM option is active, and if one of <b>Posn2D</b> or <b>Posn3D</b> is specified, one @@Ea record is hijacked each 15s, and the receiver is put back in 2D/3D mode so the the current location can be determined (for position determination, or for tracking SA). The timekeeping code is careful NOT to use the time associated with this (less accurate) 2D/3D tick in its timekeeping functions.</p> 64182007Sroberto <p>Following the initial @@Ea message are 3 additional slots for a total of four. As with the almanac, the first gets filled each time a new record becomes available, later in the code, the message is distributed to the appropriate slot. The additional slots are for messages containing 0D, 2D and 3D positions. These messages can be distinguished by different bit patterns in the last data byte of the record.</p> 65182007Sroberto <h4>Opening the Shared Memory File</h4> 66182007Sroberto <p>The shared memory segment is accessed through a file name given on a <b>SHMEM</b> card in the <tt>/etc/ntp.oncore</tt> input file. The following code could be used to open the Shared Memory Segment:</p> 67182007Sroberto <pre> 68132451Sroberto char *Buf, *file; 69132451Sroberto int size, fd; 70132451Sroberto struct stat statbuf; 71132451Sroberto 72132451Sroberto file = "/var/adm/ntpstats/ONCORE"; /* the file name on my ACCESS card */ 73132451Sroberto if ((fd=open(file, O_RDONLY)) < 0) { 74132451Sroberto fprintf(stderr, "Cant open %s\n", file); 75132451Sroberto exit(1); 76132451Sroberto } 77132451Sroberto 78132451Sroberto if (stat(file, &statbuf) < 0) { 79132451Sroberto fprintf(stderr, "Cant stat %s\n", file); 80132451Sroberto exit(1); 81132451Sroberto } 82132451Sroberto 83132451Sroberto size = statbuf.st_size; 84132451Sroberto if ((Buf=mmap(0, size, PROT_READ, MAP_SHARED, fd, (off_t) 0)) < 0) { 85132451Sroberto fprintf(stderr, "MMAP failed\n"); 86132451Sroberto exit(1); 87132451Sroberto } 88132451Sroberto</pre> 89182007Sroberto <h4>Accessing the data</h4> 90182007Sroberto <p>The following code shows how to get to the individual records.</p> 91182007Sroberto <pre> 92132451Sroberto void oncore_msg_Ea(), oncore_msg_As(), oncore_msg_Bb(); 93132451Sroberto 94132451Sroberto struct Msg { 95132451Sroberto char c[5]; 96132451Sroberto unsigned int seq; 97132451Sroberto void (*go_to)(uchar *); 98132451Sroberto }; 99132451Sroberto 100132451Sroberto struct Msg Hdr[] = { {"@@Bb", 0, &oncore_msg_Bb}, 101132451Sroberto {"@@Ea", 0, &oncore_msg_Ea}, 102132451Sroberto {"@@As", 0, &oncore_msg_As}}; 103132451Sroberto 104132451Sroberto void 105132451Sroberto read_data() 106132451Sroberto { 107132451Sroberto int i, j, k, n, iseq, jseq; 108132451Sroberto uchar *cp, *cp1; 109132451Sroberto 110132451Sroberto 111132451Sroberto for(cp=Buf+1; (n = 256*(*cp) + *(cp+1)) != 0; cp+=(n+3)) { 112132451Sroberto for (k=0; k < sizeof(Hdr)/sizeof(Hdr[0]); k++) { 113132451Sroberto if (!strncmp(cp+3, Hdr[k].c, 4)) { /* am I interested? */ 114132451Sroberto iseq = *(cp+2); 115132451Sroberto jseq = Hdr[k].seq; 116132451Sroberto Hdr[k].seq = iseq; 117132451Sroberto if (iseq > jseq) { /* has it changed? */ 118132451Sroberto /* verify checksum */ 119132451Sroberto j = 0; 120132451Sroberto cp1 = cp+3; /* points to start of oncore response */ 121132451Sroberto for (i=2; i < n-3; i++) 122132451Sroberto j ^= cp1[i]; 123132451Sroberto if (j == cp1[n-3]) { /* good checksum */ 124132451Sroberto Hdr[k].go_to(cp1); 125132451Sroberto } else { 126132451Sroberto fprintf(stderr, "Bad Checksum for %s\n", Hdr[k].c); 127132451Sroberto break; 128132451Sroberto } 129132451Sroberto } 130132451Sroberto } 131132451Sroberto } 132132451Sroberto if (!strncmp(cp+3, "@@Ea", 4)) 133132451Sroberto cp += 3*(n+3); 134132451Sroberto if (!strncmp(cp+3, "@@Cb", 4)) 135132451Sroberto cp += 34*(n+3); 136132451Sroberto } 137132451Sroberto } 138132451Sroberto 139132451Sroberto oncore_msg_Bb(uchar *buf) 140132451Sroberto { 141132451Sroberto /* process Bb messages */ 142132451Sroberto } 143132451Sroberto 144132451Sroberto oncore_msg_Ea(uchar *buf) 145132451Sroberto { 146132451Sroberto /* process Ea messages */ 147132451Sroberto } 148132451Sroberto 149132451Sroberto oncore_msg_As(uchar *buf) 150132451Sroberto { 151132451Sroberto /* process As messages */ 152132451Sroberto } 153132451Sroberto</pre> 154182007Sroberto <p>The structure Hdr contains the Identifying string for each of the messages that we want to examine, and the name of a program to call when a new message of that type is arrives. The loop can be run every few seconds to check for new data.</p> 155182007Sroberto <h4>Examples</h4> 156182007Sroberto <p>There are two complete examples available. The first plots satellite positions and the station position as affected by SA, and keeps track of the mean station position, so you can run it for periods of days to get a better station position. The second shows the effective horizon by watching satellite tracks. The examples will be found in the GNU-zipped tar file <a href="ftp://ftp.udel.edu/pub/ntp/software/OncorePlot.tar.gz">ftp://ftp.udel.edu/pub/ntp/software/OncorePlot.tar.gz</a>.</p> 157182007Sroberto <p>Try the new interface, enjoy.</p> 158182007Sroberto <hr> 159182007Sroberto <address>Reg.Clemens (reg@dwf.com), Poul-Henning Kamp (phk@FreeBSD.org)</address> 160182007Sroberto <hr> 161182007Sroberto <script type="text/javascript" language="javascript" src="scripts/footer.txt"></script> 162182007Sroberto </body> 163132451Sroberto 164280849Scy</html> 165