Index: trunk/Arduino/GSM/arduinoGSMFACT_beta_01/arduinoGSMFACT_beta_01.ino
===================================================================
--- trunk/Arduino/GSM/arduinoGSMFACT_beta_01/arduinoGSMFACT_beta_01.ino	(revision 17968)
+++ trunk/Arduino/GSM/arduinoGSMFACT_beta_01/arduinoGSMFACT_beta_01.ino	(revision 17969)
@@ -228,5 +228,5 @@
 
   compass.read();
-  heading = compass.heading((LSM303::vector){0,-1,0}) - 90 - 24;
+  heading = compass.heading((LSM303::vector<int>){0,-1,0}) - 90 - 24;
   if( heading < 0 ) heading = heading + 360;
   //server.println(heading);
Index: trunk/Arduino/GSM/arduinoGSMFACT_beta_02_nogms/arduinoGSMFACT_beta_02_nogms.ino
===================================================================
--- trunk/Arduino/GSM/arduinoGSMFACT_beta_02_nogms/arduinoGSMFACT_beta_02_nogms.ino	(revision 17968)
+++ trunk/Arduino/GSM/arduinoGSMFACT_beta_02_nogms/arduinoGSMFACT_beta_02_nogms.ino	(revision 17969)
@@ -234,5 +234,5 @@
 
   compass.read();
-  heading = compass.heading((LSM303::vector){0,-1,0}) - 90 - 24;
+  heading = compass.heading((LSM303::vector<int>){0,-1,0}) - 90 - 24;
   if( heading < 0 ) heading = heading + 360;
   //server.println(heading);
Index: trunk/Arduino/GSM/libraries/LSM303/LICENSE.txt
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/LICENSE.txt	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/LICENSE.txt	(revision 17969)
@@ -0,0 +1,25 @@
+Copyright (c) 2013 Pololu Corporation.  For more information, see
+
+http://www.pololu.com/
+http://forum.pololu.com/
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
Index: trunk/Arduino/GSM/libraries/LSM303/LSM303.cpp
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/LSM303.cpp	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/LSM303.cpp	(revision 17969)
@@ -0,0 +1,570 @@
+#include <LSM303.h>
+#include <Wire.h>
+#include <math.h>
+
+// Defines ////////////////////////////////////////////////////////////////
+
+// The Arduino two-wire interface uses a 7-bit number for the address,
+// and sets the last bit correctly based on reads and writes
+#define D_SA0_HIGH_ADDRESS              0b0011101 // D with SA0 high
+#define D_SA0_LOW_ADDRESS               0b0011110 // D with SA0 low or non-D magnetometer
+#define NON_D_MAG_ADDRESS               0b0011110 // D with SA0 low or non-D magnetometer
+#define NON_D_ACC_SA0_LOW_ADDRESS       0b0011000 // non-D accelerometer with SA0 low
+#define NON_D_ACC_SA0_HIGH_ADDRESS      0b0011001 // non-D accelerometer with SA0 high
+
+#define TEST_REG_NACK -1
+
+#define D_WHO_ID    0x49
+#define DLM_WHO_ID  0x3C
+
+// Constructors ////////////////////////////////////////////////////////////////
+
+LSM303::LSM303(void)
+{
+  /*
+  These values lead to an assumed magnetometer bias of 0.
+  Use the Calibrate example program to determine appropriate values
+  for your particular unit. The Heading example demonstrates how to
+  adjust these values in your own sketch.
+  */
+  m_min = (LSM303::vector<int16_t>){-32767, -32767, -32767};
+  m_max = (LSM303::vector<int16_t>){+32767, +32767, +32767};
+
+  _device = device_auto;
+
+  io_timeout = 0;  // 0 = no timeout
+  did_timeout = false;
+}
+
+// Public Methods //////////////////////////////////////////////////////////////
+
+// Did a timeout occur in readAcc(), readMag(), or read() since the last call to timeoutOccurred()?
+bool LSM303::timeoutOccurred()
+{
+  bool tmp = did_timeout;
+  did_timeout = false;
+  return tmp;
+
+}
+
+void LSM303::setTimeout(unsigned int timeout)
+{
+  io_timeout = timeout;
+}
+
+unsigned int LSM303::getTimeout()
+{
+  return io_timeout;
+}
+
+bool LSM303::init(deviceType device, sa0State sa0)
+{
+  // determine device type if necessary
+  if (device == device_auto)
+  {
+    if (testReg(D_SA0_HIGH_ADDRESS, WHO_AM_I) == D_WHO_ID)
+    {
+      // device responds to address 0011101 with D ID; it's a D with SA0 high
+      device = device_D;
+      sa0 = sa0_high;
+    }
+    else if (testReg(D_SA0_LOW_ADDRESS, WHO_AM_I) == D_WHO_ID)
+    {
+      // device responds to address 0011110 with D ID; it's a D with SA0 low
+      device = device_D;
+      sa0 = sa0_low;
+    }
+    // Remaining possibilities: DLHC, DLM, or DLH. DLHC seems to respond to WHO_AM_I request the
+    // same way as DLM, even though this register isn't documented in its datasheet, so instead,
+    // guess if it's a DLHC based on acc address (Pololu boards pull SA0 low on DLM and DLH;
+    // DLHC doesn't have SA0 but uses same acc address as DLH/DLM with SA0 high).
+    else if (testReg(NON_D_ACC_SA0_HIGH_ADDRESS, CTRL_REG1_A) != TEST_REG_NACK)
+    {
+      // device responds to address 0011001; guess that it's a DLHC
+      device = device_DLHC;
+      sa0 = sa0_high;
+    }
+    // Remaining possibilities: DLM or DLH. Check acc with SA0 low address to make sure it's responsive
+    else if (testReg(NON_D_ACC_SA0_LOW_ADDRESS, CTRL_REG1_A) != TEST_REG_NACK)
+    {
+      // device responds to address 0011000 with DLM ID; guess that it's a DLM
+      sa0 = sa0_low;
+
+      // Now check WHO_AM_I_M
+      if (testReg(NON_D_MAG_ADDRESS, WHO_AM_I_M) == DLM_WHO_ID)
+      {
+        device = device_DLM;
+      }
+      else
+      {
+        device = device_DLH;
+      }
+    }
+    else
+    {
+      // device hasn't responded meaningfully, so give up
+      return false;
+    }
+  }
+
+  // determine SA0 if necessary
+  if (sa0 == sa0_auto)
+  {
+    if (device == device_D)
+    {
+      if (testReg(D_SA0_HIGH_ADDRESS, WHO_AM_I) == D_WHO_ID)
+      {
+        sa0 = sa0_high;
+      }
+      else if (testReg(D_SA0_LOW_ADDRESS, WHO_AM_I) == D_WHO_ID)
+      {
+        sa0 = sa0_low;
+      }
+      else
+      {
+        // no response on either possible address; give up
+        return false;
+      }
+    }
+    else if (device == device_DLM || device == device_DLH)
+    {
+      if (testReg(NON_D_ACC_SA0_HIGH_ADDRESS, CTRL_REG1_A) != TEST_REG_NACK)
+      {
+        sa0 = sa0_high;
+      }
+      else if (testReg(NON_D_ACC_SA0_LOW_ADDRESS, CTRL_REG1_A) != TEST_REG_NACK)
+      {
+        sa0 = sa0_low;
+      }
+      else
+      {
+        // no response on either possible address; give up
+        return false;
+      }
+    }
+  }
+
+  _device = device;
+
+  // set device addresses and translated register addresses
+  switch (device)
+  {
+    case device_D:
+      acc_address = mag_address = (sa0 == sa0_high) ? D_SA0_HIGH_ADDRESS : D_SA0_LOW_ADDRESS;
+      translated_regs[-OUT_X_L_M] = D_OUT_X_L_M;
+      translated_regs[-OUT_X_H_M] = D_OUT_X_H_M;
+      translated_regs[-OUT_Y_L_M] = D_OUT_Y_L_M;
+      translated_regs[-OUT_Y_H_M] = D_OUT_Y_H_M;
+      translated_regs[-OUT_Z_L_M] = D_OUT_Z_L_M;
+      translated_regs[-OUT_Z_H_M] = D_OUT_Z_H_M;
+      break;
+
+    case device_DLHC:
+      acc_address = NON_D_ACC_SA0_HIGH_ADDRESS; // DLHC doesn't have SA0 but uses same acc address as DLH/DLM with SA0 high
+      mag_address = NON_D_MAG_ADDRESS;
+      translated_regs[-OUT_X_H_M] = DLHC_OUT_X_H_M;
+      translated_regs[-OUT_X_L_M] = DLHC_OUT_X_L_M;
+      translated_regs[-OUT_Y_H_M] = DLHC_OUT_Y_H_M;
+      translated_regs[-OUT_Y_L_M] = DLHC_OUT_Y_L_M;
+      translated_regs[-OUT_Z_H_M] = DLHC_OUT_Z_H_M;
+      translated_regs[-OUT_Z_L_M] = DLHC_OUT_Z_L_M;
+      break;
+
+    case device_DLM:
+      acc_address = (sa0 == sa0_high) ? NON_D_ACC_SA0_HIGH_ADDRESS : NON_D_ACC_SA0_LOW_ADDRESS;
+      mag_address = NON_D_MAG_ADDRESS;
+      translated_regs[-OUT_X_H_M] = DLM_OUT_X_H_M;
+      translated_regs[-OUT_X_L_M] = DLM_OUT_X_L_M;
+      translated_regs[-OUT_Y_H_M] = DLM_OUT_Y_H_M;
+      translated_regs[-OUT_Y_L_M] = DLM_OUT_Y_L_M;
+      translated_regs[-OUT_Z_H_M] = DLM_OUT_Z_H_M;
+      translated_regs[-OUT_Z_L_M] = DLM_OUT_Z_L_M;
+      break;
+
+    case device_DLH:
+      acc_address = (sa0 == sa0_high) ? NON_D_ACC_SA0_HIGH_ADDRESS : NON_D_ACC_SA0_LOW_ADDRESS;
+      mag_address = NON_D_MAG_ADDRESS;
+      translated_regs[-OUT_X_H_M] = DLH_OUT_X_H_M;
+      translated_regs[-OUT_X_L_M] = DLH_OUT_X_L_M;
+      translated_regs[-OUT_Y_H_M] = DLH_OUT_Y_H_M;
+      translated_regs[-OUT_Y_L_M] = DLH_OUT_Y_L_M;
+      translated_regs[-OUT_Z_H_M] = DLH_OUT_Z_H_M;
+      translated_regs[-OUT_Z_L_M] = DLH_OUT_Z_L_M;
+      break;
+  }
+  return true;
+}
+
+/*
+Enables the LSM303's accelerometer and magnetometer. Also:
+- Sets sensor full scales (gain) to default power-on values, which are
+  +/- 2 g for accelerometer and +/- 1.3 gauss for magnetometer
+  (+/- 4 gauss on LSM303D).
+- Selects 50 Hz ODR (output data rate) for accelerometer and 7.5 Hz
+  ODR for magnetometer (6.25 Hz on LSM303D). (These are the ODR
+  settings for which the electrical characteristics are specified in
+  the datasheets.)
+- Enables high resolution modes (if available).
+Note that this function will also reset other settings controlled by
+the registers it writes to.
+*/
+void LSM303::enableDefault(void)
+{
+
+  if (_device == device_D)
+  {
+    // Accelerometer
+
+    // 0x57 = 0b01010111
+    // AFS = 0 (+/- 2 g full scale)
+    writeReg(CTRL2, 0x00);
+
+    // 0x57 = 0b01010111
+    // AODR = 0101 (50 Hz ODR); AZEN = AYEN = AXEN = 1 (all axes enabled)
+    writeReg(CTRL1, 0x57);
+
+    // Magnetometer
+
+    // 0x64 = 0b01100100
+    // M_RES = 11 (high resolution mode); M_ODR = 001 (6.25 Hz ODR)
+    writeReg(CTRL5, 0x64);
+
+    // 0x20 = 0b00100000
+    // MFS = 01 (+/- 4 gauss full scale)
+    writeReg(CTRL6, 0x20);
+
+    // 0x00 = 0b00000000
+    // MLP = 0 (low power mode off); MD = 00 (continuous-conversion mode)
+    writeReg(CTRL7, 0x00);
+  }
+  else if (_device == device_DLHC)
+  {
+    // Accelerometer
+
+    // 0x08 = 0b00001000
+    // FS = 00 (+/- 2 g full scale); HR = 1 (high resolution enable)
+    writeAccReg(CTRL_REG4_A, 0x08);
+
+    // 0x47 = 0b01000111
+    // ODR = 0100 (50 Hz ODR); LPen = 0 (normal mode); Zen = Yen = Xen = 1 (all axes enabled)
+    writeAccReg(CTRL_REG1_A, 0x47);
+
+    // Magnetometer
+
+    // 0x0C = 0b00001100
+    // DO = 011 (7.5 Hz ODR)
+    writeMagReg(CRA_REG_M, 0x0C);
+
+    // 0x20 = 0b00100000
+    // GN = 001 (+/- 1.3 gauss full scale)
+    writeMagReg(CRB_REG_M, 0x20);
+
+    // 0x00 = 0b00000000
+    // MD = 00 (continuous-conversion mode)
+    writeMagReg(MR_REG_M, 0x00);
+  }
+  else // DLM, DLH
+  {
+    // Accelerometer
+
+    // 0x00 = 0b00000000
+    // FS = 00 (+/- 2 g full scale)
+    writeAccReg(CTRL_REG4_A, 0x00);
+
+    // 0x27 = 0b00100111
+    // PM = 001 (normal mode); DR = 00 (50 Hz ODR); Zen = Yen = Xen = 1 (all axes enabled)
+    writeAccReg(CTRL_REG1_A, 0x27);
+
+    // Magnetometer
+
+    // 0x0C = 0b00001100
+    // DO = 011 (7.5 Hz ODR)
+    writeMagReg(CRA_REG_M, 0x0C);
+
+    // 0x20 = 0b00100000
+    // GN = 001 (+/- 1.3 gauss full scale)
+    writeMagReg(CRB_REG_M, 0x20);
+
+    // 0x00 = 0b00000000
+    // MD = 00 (continuous-conversion mode)
+    writeMagReg(MR_REG_M, 0x00);
+  }
+}
+
+// Writes an accelerometer register
+void LSM303::writeAccReg(regAddr reg, byte value)
+{
+  Wire.beginTransmission(acc_address);
+  Wire.write((byte)reg);
+  Wire.write(value);
+  last_status = Wire.endTransmission();
+}
+
+// Reads an accelerometer register
+byte LSM303::readAccReg(regAddr reg)
+{
+  byte value;
+
+  Wire.beginTransmission(acc_address);
+  Wire.write((byte)reg);
+  last_status = Wire.endTransmission();
+  Wire.requestFrom(acc_address, (byte)1);
+  value = Wire.read();
+  Wire.endTransmission();
+
+  return value;
+}
+
+// Writes a magnetometer register
+void LSM303::writeMagReg(regAddr reg, byte value)
+{
+  Wire.beginTransmission(mag_address);
+  Wire.write((byte)reg);
+  Wire.write(value);
+  last_status = Wire.endTransmission();
+}
+
+// Reads a magnetometer register
+byte LSM303::readMagReg(regAddr reg)
+{
+  byte value;
+
+  // if dummy register address (magnetometer Y/Z), look up actual translated address (based on device type)
+  if (reg < 0)
+  {
+    reg = translated_regs[-reg];
+  }
+
+  Wire.beginTransmission(mag_address);
+  Wire.write((byte)reg);
+  last_status = Wire.endTransmission();
+  Wire.requestFrom(mag_address, (byte)1);
+  value = Wire.read();
+  Wire.endTransmission();
+
+  return value;
+}
+
+void LSM303::writeReg(regAddr reg, byte value)
+{
+  // mag address == acc_address for LSM303D, so it doesn't really matter which one we use.
+  // Use writeMagReg so it can translate OUT_[XYZ]_[HL]_M
+  if (_device == device_D || reg < CTRL_REG1_A)
+  {
+    writeMagReg(reg, value);
+  }
+  else
+  {
+    writeAccReg(reg, value);
+  }
+}
+
+// Note that this function will not work for reading TEMP_OUT_H_M and TEMP_OUT_L_M on the DLHC.
+// To read those two registers, use readMagReg() instead.
+byte LSM303::readReg(regAddr reg)
+{
+  // mag address == acc_address for LSM303D, so it doesn't really matter which one we use.
+  // Use writeMagReg so it can translate OUT_[XYZ]_[HL]_M
+  if (_device == device_D || reg < CTRL_REG1_A)
+  {
+    return readMagReg(reg);
+  }
+  else
+  {
+    return readAccReg(reg);
+  }
+}
+
+// Reads the 3 accelerometer channels and stores them in vector a
+void LSM303::readAcc(void)
+{
+  Wire.beginTransmission(acc_address);
+  // assert the MSB of the address to get the accelerometer
+  // to do slave-transmit subaddress updating.
+  Wire.write(OUT_X_L_A | (1 << 7));
+  last_status = Wire.endTransmission();
+  Wire.requestFrom(acc_address, (byte)6);
+
+  unsigned int millis_start = millis();
+  while (Wire.available() < 6) {
+    if (io_timeout > 0 && ((unsigned int)millis() - millis_start) > io_timeout)
+    {
+      did_timeout = true;
+      return;
+    }
+  }
+
+  byte xla = Wire.read();
+  byte xha = Wire.read();
+  byte yla = Wire.read();
+  byte yha = Wire.read();
+  byte zla = Wire.read();
+  byte zha = Wire.read();
+
+  // combine high and low bytes
+  // This no longer drops the lowest 4 bits of the readings from the DLH/DLM/DLHC, which are always 0
+  // (12-bit resolution, left-aligned). The D has 16-bit resolution
+  a.x = (int16_t)(xha << 8 | xla);
+  a.y = (int16_t)(yha << 8 | yla);
+  a.z = (int16_t)(zha << 8 | zla);
+}
+
+// Reads the 3 magnetometer channels and stores them in vector m
+void LSM303::readMag(void)
+{
+  Wire.beginTransmission(mag_address);
+  // If LSM303D, assert MSB to enable subaddress updating
+  // OUT_X_L_M comes first on D, OUT_X_H_M on others
+  Wire.write((_device == device_D) ? translated_regs[-OUT_X_L_M] | (1 << 7) : translated_regs[-OUT_X_H_M]);
+  last_status = Wire.endTransmission();
+  Wire.requestFrom(mag_address, (byte)6);
+
+  unsigned int millis_start = millis();
+  while (Wire.available() < 6) {
+    if (io_timeout > 0 && ((unsigned int)millis() - millis_start) > io_timeout)
+    {
+      did_timeout = true;
+      return;
+    }
+  }
+
+  byte xlm, xhm, ylm, yhm, zlm, zhm;
+
+  if (_device == device_D)
+  {
+    /// D: X_L, X_H, Y_L, Y_H, Z_L, Z_H
+    xlm = Wire.read();
+    xhm = Wire.read();
+    ylm = Wire.read();
+    yhm = Wire.read();
+    zlm = Wire.read();
+    zhm = Wire.read();
+  }
+  else
+  {
+    // DLHC, DLM, DLH: X_H, X_L...
+    xhm = Wire.read();
+    xlm = Wire.read();
+
+    if (_device == device_DLH)
+    {
+      // DLH: ...Y_H, Y_L, Z_H, Z_L
+      yhm = Wire.read();
+      ylm = Wire.read();
+      zhm = Wire.read();
+      zlm = Wire.read();
+    }
+    else
+    {
+      // DLM, DLHC: ...Z_H, Z_L, Y_H, Y_L
+      zhm = Wire.read();
+      zlm = Wire.read();
+      yhm = Wire.read();
+      ylm = Wire.read();
+    }
+  }
+
+  // combine high and low bytes
+  m.x = (int16_t)(xhm << 8 | xlm);
+  m.y = (int16_t)(yhm << 8 | ylm);
+  m.z = (int16_t)(zhm << 8 | zlm);
+}
+
+// Reads all 6 channels of the LSM303 and stores them in the object variables
+void LSM303::read(void)
+{
+  readAcc();
+  readMag();
+}
+
+/*
+Returns the angular difference in the horizontal plane between a
+default vector and north, in degrees.
+
+The default vector here is chosen to point along the surface of the
+PCB, in the direction of the top of the text on the silkscreen.
+This is the +X axis on the Pololu LSM303D carrier and the -Y axis on
+the Pololu LSM303DLHC, LSM303DLM, and LSM303DLH carriers.
+*/
+float LSM303::heading(void)
+{
+  if (_device == device_D)
+  {
+    return heading((vector<int>){1, 0, 0});
+  }
+  else
+  {
+    return heading((vector<int>){0, -1, 0});
+  }
+}
+
+/*
+Returns the angular difference in the horizontal plane between the
+"from" vector and north, in degrees.
+
+Description of heading algorithm:
+Shift and scale the magnetic reading based on calibration data to find
+the North vector. Use the acceleration readings to determine the Up
+vector (gravity is measured as an upward acceleration). The cross
+product of North and Up vectors is East. The vectors East and North
+form a basis for the horizontal plane. The From vector is projected
+into the horizontal plane and the angle between the projected vector
+and horizontal north is returned.
+*/
+template <typename T> float LSM303::heading(vector<T> from)
+{
+    vector<int32_t> temp_m = {m.x, m.y, m.z};
+
+    // subtract offset (average of min and max) from magnetometer readings
+    temp_m.x -= ((int32_t)m_min.x + m_max.x) / 2;
+    temp_m.y -= ((int32_t)m_min.y + m_max.y) / 2;
+    temp_m.z -= ((int32_t)m_min.z + m_max.z) / 2;
+
+    // compute E and N
+    vector<float> E;
+    vector<float> N;
+    vector_cross(&temp_m, &a, &E);
+    vector_normalize(&E);
+    vector_cross(&a, &E, &N);
+    vector_normalize(&N);
+
+    // compute heading
+    float heading = atan2(vector_dot(&E, &from), vector_dot(&N, &from)) * 180 / M_PI;
+    if (heading < 0) heading += 360;
+    return heading;
+}
+
+template <typename Ta, typename Tb, typename To> void LSM303::vector_cross(const vector<Ta> *a,const vector<Tb> *b, vector<To> *out)
+{
+  out->x = (a->y * b->z) - (a->z * b->y);
+  out->y = (a->z * b->x) - (a->x * b->z);
+  out->z = (a->x * b->y) - (a->y * b->x);
+}
+
+template <typename Ta, typename Tb> float LSM303::vector_dot(const vector<Ta> *a, const vector<Tb> *b)
+{
+  return (a->x * b->x) + (a->y * b->y) + (a->z * b->z);
+}
+
+void LSM303::vector_normalize(vector<float> *a)
+{
+  float mag = sqrt(vector_dot(a, a));
+  a->x /= mag;
+  a->y /= mag;
+  a->z /= mag;
+}
+
+// Private Methods //////////////////////////////////////////////////////////////
+
+int LSM303::testReg(byte address, regAddr reg)
+{
+  Wire.beginTransmission(address);
+  Wire.write((byte)reg);
+  last_status = Wire.endTransmission();
+
+  Wire.requestFrom(address, (byte)1);
+  if (Wire.available())
+    return Wire.read();
+  else
+    return TEST_REG_NACK;
+}
Index: trunk/Arduino/GSM/libraries/LSM303/LSM303.h
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/LSM303.h	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/LSM303.h	(revision 17969)
@@ -0,0 +1,218 @@
+#ifndef LSM303_h
+#define LSM303_h
+
+#include <Arduino.h> // for byte data type
+
+class LSM303
+{
+  public:
+    template <typename T> struct vector
+    {
+      T x, y, z;
+    };
+
+    enum deviceType { device_DLH, device_DLM, device_DLHC, device_D, device_auto };
+    enum sa0State { sa0_low, sa0_high, sa0_auto };
+
+    // register addresses
+    enum regAddr
+    {
+      TEMP_OUT_L        = 0x05, // D
+      TEMP_OUT_H        = 0x06, // D
+
+      STATUS_M          = 0x07, // D
+
+      INT_CTRL_M        = 0x12, // D
+      INT_SRC_M         = 0x13, // D
+      INT_THS_L_M       = 0x14, // D
+      INT_THS_H_M       = 0x15, // D
+
+      OFFSET_X_L_M      = 0x16, // D
+      OFFSET_X_H_M      = 0x17, // D
+      OFFSET_Y_L_M      = 0x18, // D
+      OFFSET_Y_H_M      = 0x19, // D
+      OFFSET_Z_L_M      = 0x1A, // D
+      OFFSET_Z_H_M      = 0x1B, // D
+      REFERENCE_X       = 0x1C, // D
+      REFERENCE_Y       = 0x1D, // D
+      REFERENCE_Z       = 0x1E, // D
+
+      CTRL0             = 0x1F, // D
+      CTRL1             = 0x20, // D
+      CTRL_REG1_A       = 0x20, // DLH, DLM, DLHC
+      CTRL2             = 0x21, // D
+      CTRL_REG2_A       = 0x21, // DLH, DLM, DLHC
+      CTRL3             = 0x22, // D
+      CTRL_REG3_A       = 0x22, // DLH, DLM, DLHC
+      CTRL4             = 0x23, // D
+      CTRL_REG4_A       = 0x23, // DLH, DLM, DLHC
+      CTRL5             = 0x24, // D
+      CTRL_REG5_A       = 0x24, // DLH, DLM, DLHC
+      CTRL6             = 0x25, // D
+      CTRL_REG6_A       = 0x25, // DLHC
+      HP_FILTER_RESET_A = 0x25, // DLH, DLM
+      CTRL7             = 0x26, // D
+      REFERENCE_A       = 0x26, // DLH, DLM, DLHC
+      STATUS_A          = 0x27, // D
+      STATUS_REG_A      = 0x27, // DLH, DLM, DLHC
+
+      OUT_X_L_A         = 0x28,
+      OUT_X_H_A         = 0x29,
+      OUT_Y_L_A         = 0x2A,
+      OUT_Y_H_A         = 0x2B,
+      OUT_Z_L_A         = 0x2C,
+      OUT_Z_H_A         = 0x2D,
+
+      FIFO_CTRL         = 0x2E, // D
+      FIFO_CTRL_REG_A   = 0x2E, // DLHC
+      FIFO_SRC          = 0x2F, // D
+      FIFO_SRC_REG_A    = 0x2F, // DLHC
+
+      IG_CFG1           = 0x30, // D
+      INT1_CFG_A        = 0x30, // DLH, DLM, DLHC
+      IG_SRC1           = 0x31, // D
+      INT1_SRC_A        = 0x31, // DLH, DLM, DLHC
+      IG_THS1           = 0x32, // D
+      INT1_THS_A        = 0x32, // DLH, DLM, DLHC
+      IG_DUR1           = 0x33, // D
+      INT1_DURATION_A   = 0x33, // DLH, DLM, DLHC
+      IG_CFG2           = 0x34, // D
+      INT2_CFG_A        = 0x34, // DLH, DLM, DLHC
+      IG_SRC2           = 0x35, // D
+      INT2_SRC_A        = 0x35, // DLH, DLM, DLHC
+      IG_THS2           = 0x36, // D
+      INT2_THS_A        = 0x36, // DLH, DLM, DLHC
+      IG_DUR2           = 0x37, // D
+      INT2_DURATION_A   = 0x37, // DLH, DLM, DLHC
+
+      CLICK_CFG         = 0x38, // D
+      CLICK_CFG_A       = 0x38, // DLHC
+      CLICK_SRC         = 0x39, // D
+      CLICK_SRC_A       = 0x39, // DLHC
+      CLICK_THS         = 0x3A, // D
+      CLICK_THS_A       = 0x3A, // DLHC
+      TIME_LIMIT        = 0x3B, // D
+      TIME_LIMIT_A      = 0x3B, // DLHC
+      TIME_LATENCY      = 0x3C, // D
+      TIME_LATENCY_A    = 0x3C, // DLHC
+      TIME_WINDOW       = 0x3D, // D
+      TIME_WINDOW_A     = 0x3D, // DLHC
+
+      Act_THS           = 0x3E, // D
+      Act_DUR           = 0x3F, // D
+
+      CRA_REG_M         = 0x00, // DLH, DLM, DLHC
+      CRB_REG_M         = 0x01, // DLH, DLM, DLHC
+      MR_REG_M          = 0x02, // DLH, DLM, DLHC
+
+      SR_REG_M          = 0x09, // DLH, DLM, DLHC
+      IRA_REG_M         = 0x0A, // DLH, DLM, DLHC
+      IRB_REG_M         = 0x0B, // DLH, DLM, DLHC
+      IRC_REG_M         = 0x0C, // DLH, DLM, DLHC
+
+      WHO_AM_I_M        = 0x0F, // DLM
+      WHO_AM_I          = 0x0F, // D
+
+      TEMP_OUT_H_M      = 0x31, // DLHC
+      TEMP_OUT_L_M      = 0x32, // DLHC
+
+
+      // dummy addresses for registers in different locations on different devices;
+      // the library translates these based on device type
+      // value with sign flipped is used as index into translated_regs array
+
+      OUT_X_H_M         = -1,
+      OUT_X_L_M         = -2,
+      OUT_Y_H_M         = -3,
+      OUT_Y_L_M         = -4,
+      OUT_Z_H_M         = -5,
+      OUT_Z_L_M         = -6,
+      // update dummy_reg_count if registers are added here!
+
+      // device-specific register addresses
+
+      DLH_OUT_X_H_M     = 0x03,
+      DLH_OUT_X_L_M     = 0x04,
+      DLH_OUT_Y_H_M     = 0x05,
+      DLH_OUT_Y_L_M     = 0x06,
+      DLH_OUT_Z_H_M     = 0x07,
+      DLH_OUT_Z_L_M     = 0x08,
+
+      DLM_OUT_X_H_M     = 0x03,
+      DLM_OUT_X_L_M     = 0x04,
+      DLM_OUT_Z_H_M     = 0x05,
+      DLM_OUT_Z_L_M     = 0x06,
+      DLM_OUT_Y_H_M     = 0x07,
+      DLM_OUT_Y_L_M     = 0x08,
+
+      DLHC_OUT_X_H_M    = 0x03,
+      DLHC_OUT_X_L_M    = 0x04,
+      DLHC_OUT_Z_H_M    = 0x05,
+      DLHC_OUT_Z_L_M    = 0x06,
+      DLHC_OUT_Y_H_M    = 0x07,
+      DLHC_OUT_Y_L_M    = 0x08,
+
+      D_OUT_X_L_M       = 0x08,
+      D_OUT_X_H_M       = 0x09,
+      D_OUT_Y_L_M       = 0x0A,
+      D_OUT_Y_H_M       = 0x0B,
+      D_OUT_Z_L_M       = 0x0C,
+      D_OUT_Z_H_M       = 0x0D
+    };
+
+    vector<int16_t> a; // accelerometer readings
+    vector<int16_t> m; // magnetometer readings
+    vector<int16_t> m_max; // maximum magnetometer values, used for calibration
+    vector<int16_t> m_min; // minimum magnetometer values, used for calibration
+
+    byte last_status; // status of last I2C transmission
+
+    LSM303(void);
+
+    bool init(deviceType device = device_auto, sa0State sa0 = sa0_auto);
+    byte getDeviceType(void) { return _device; }
+
+    void enableDefault(void);
+
+    void writeAccReg(regAddr reg, byte value);
+    byte readAccReg(regAddr reg);
+    void writeMagReg(regAddr reg, byte value);
+    byte readMagReg(regAddr reg);
+
+    void writeReg(regAddr reg, byte value);
+    byte readReg(regAddr reg);
+
+    void readAcc(void);
+    void readMag(void);
+    void read(void);
+
+    void setTimeout(unsigned int timeout);
+    unsigned int getTimeout(void);
+    bool timeoutOccurred(void);
+
+    float heading(void);
+    template <typename T> float heading(vector<T> from);
+
+    // vector functions
+    template <typename Ta, typename Tb, typename To> static void vector_cross(const vector<Ta> *a, const vector<Tb> *b, vector<To> *out);
+    template <typename Ta, typename Tb> static float vector_dot(const vector<Ta> *a,const vector<Tb> *b);
+    static void vector_normalize(vector<float> *a);
+
+  private:
+    deviceType _device; // chip type (DLH, DLM, or DLHC)
+    byte acc_address;
+    byte mag_address;
+
+    static const int dummy_reg_count = 6;
+    regAddr translated_regs[dummy_reg_count + 1]; // index 0 not used
+
+    unsigned int io_timeout;
+    bool did_timeout;
+
+    int testReg(byte address, regAddr reg);
+};
+
+#endif
+
+
+
Index: trunk/Arduino/GSM/libraries/LSM303/README.textile
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/README.textile	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/README.textile	(revision 17969)
@@ -0,0 +1,147 @@
+h1. Arduino library for Pololu LSM303 boards
+
+Version: 2.0.0
+Release Date: 2013-11-27
+"www.pololu.com":http://www.pololu.com/
+
+h2. Summary
+
+This is a library for the "Arduino":http://pololu.com/catalog/product/2191 that interfaces with LSM303D, LSM303DLHC, LSM303DLM, and LSM303DLH 3D compass and accelerometer ICs on Pololu boards. It makes it simple to read the raw accelerometer and magnetometer data from these boards:
+
+* "LSM303D 3D compass and accelerometer carrier":http://www.pololu.com/catalog/product/2127
+* "LSM303DLHC 3D compass and accelerometer carrier":http://www.pololu.com/catalog/product/2124
+* "LSM303DLM 3D compass and accelerometer carrier":http://www.pololu.com/catalog/product/1273
+* "MinIMU-9 v2 (L3GD20 and LSM303DLHC carrier&#41;":http://www.pololu.com/catalog/product/1268
+* "AltIMU-10 (L3GD20, LSM303DLHC, and LSM331AP carrier&#41;":http://www.pololu.com/catalog/product/1269
+* "LSM303DLH 3D compass and accelerometer carrier":http://www.pololu.com/catalog/product/1250 (discontinued)
+* "MinIMU-9 (L3G4200D and LSM303DLM carrier&#41;":http://www.pololu.com/catalog/product/1265 (discontinued)
+* "MinIMU-9 (L3G4200D and LSM303DLH carrier&#41;":http://www.pololu.com/catalog/product/1264 (discontinued)
+
+The library also includes a function for computing the tilt-compensated heading for those looking to use the LSM303 as a tilt-compensated compass.
+
+h2. Getting Started
+
+h3. Software
+
+Download the archive from "GitHub":https://github.com/pololu/LSM303, decompress it, and move the "LSM303" folder into the "libraries" subdirectory inside your Arduino sketchbook directory. You can view your sketchbook location by selecting File->Preferences in the Arduino environment; if there is not already a "libraries" folder in that location, you should create it yourself. After installing the library, restart the Arduino environment so it can find the LSM303 library and its examples.
+
+h3. Hardware
+
+Make the following connections with wires between the Arduino and the LSM303 board:
+
+h4. Arduino Uno R3, Leonardo, Mega 2560
+
+pre. Arduino      LSM303 board
+-------------------------
+     5V  ->  VIN
+    GND  ->  GND
+    SDA  ->  SDA
+    SCL  ->  SCL
+
+h4. Arduino Micro
+
+pre. Arduino      LSM303 board
+-------------------------
+     5V  ->  VIN
+    GND  ->  GND
+      2  ->  SDA
+      3  ->  SCL
+
+h4. Arduino Uno (up to R2), Duemilanove, etc.
+
+pre. Arduino      LSM303 board
+-------------------------
+     5V  ->  VIN
+    GND  ->  GND
+     A4  ->  SDA
+     A5  ->  SCL
+
+h2. Example Programs
+
+Open an example code sketch by selecting File->Examples->LSM303->example_name
+
+h3. Serial
+
+This program continuously reads the accelerometer and magnetometer, communicating the readings over the serial interface. You can display the readings with the Arduino Serial Monitor.
+
+Example output:
+
+pre. A:    192  -1040 -17168    M:   -512     27    144
+A:    288  -1040 -17232    M:   -511     26    143
+A:     16  -1104 -17216    M:   -511     27    144
+
+See the comments in this sketch for some notes on how to convert the raw sensor values to units of g and gauss.
+
+h3. Calibrate
+
+This program is similar to the Serial example, but instead of printing the most recent readings, it prints a running minimum and maximum of the readings from each magnetometer axis. These values can be used to calibrate the @heading()@ functions and the Heading example after moving the LSM303 through every possible orientation.
+
+h3. Heading
+
+This program uses readings from the accelerometer and magnetometer to calculate a tilt-compensated compass heading (in degrees relative to a default vector), which is communicated serially and can be displayed with the Arduino Serial Monitor. The default vector is chosen to point along the surface of the PCB, in the direction of the top of the text on the silkscreen. (This is the +X axis on the Pololu LSM303D carrier and the -Y axis on
+the Pololu LSM303DLHC, LSM303DLM, and LSM303DLH carriers.) See the comments if you want to use a different reference vector.
+
+For the most accurate results, you should replace the values of @m_min@ and @m_max@ assigned in the @setup()@ function with your own values obtained from the Calibrate example.
+
+h2. Other Library Applications
+
+These programs make use of the LSM303 library but are not included with in the library archive or repository.
+
+- "MinIMU-9 + Arduino AHRS":https://github.com/pololu/minimu-9-ahrs-arduino := This sketch allows an Arduino connected to a MinIMU-9 or AltIMU-10 to function as an attitude and heading reference system, calculating estimated roll, pitch, and yaw angles from sensor readings that can be visualized with a 3D test program on a PC. It is based on the work of Jordi Munoz, William Premerlani, Jose Julio, and Doug Weibel.
+- "Pololu_Open_IMU":https://github.com/mikeshub/Pololu_Open_IMU/tree/master/Pololu_Open_IMU by mikeshub := This is an alternative AHRS implementation that uses the "Madgwick algorithm":http://www.x-io.co.uk/open-source-imu-and-ahrs-algorithms/.
+- "ascii_graph":https://gist.github.com/drewtm/9081341 by drewtm := This sketch outputs a text-based graph of LSM303 accelerometer and L3G gyro data, providing a quick way to check whether the sensors are working as expected.
+
+h2. Library Reference
+
+- @vector<int16_t> a@ := The last values read from the accelerometer.
+- @vector<int16_t> m@ := The last values read from the magnetometer.
+- @vector<int16_t> m_min@ := Lower bounds (minimum values) for the magnetometer readings on each axis; set this appropriately to calibrate @heading()@.
+- @vector<int16_t> m_max@ := Upper bounds (maximum values) for the magnetometer readings on each axis; set this appropriately to calibrate @heading()@.
+- @byte last_status@ := The status of the last I2C transmission. See the "@Wire.endTransmission()@ documentation":http://arduino.cc/en/Reference/WireEndTransmission for return values.
+
+- @LSM303(void)@ := Constructor; initializes @m_min@ and @m_max@ with placeholder values.
+- @bool init(deviceType device, sa0State sa0)@ := Initializes the library with the device being used (@device_DLH@, @device_DLM@, @device_DLHC@, @device_D@, or @device_auto@) and the state of the SA0 pin (@sa0_low@, @sa0_high@, or @sa0_auto@), which determines the least significant bit(s) of the accelerometer address on some devices. Constants for these arguments are defined in LSM303.h. Both of these arguments are optional; if they are not specified, the library will try to automatically detect the device and accelerometer address[1]. A boolean is returned indicating whether an LSM303 device was successfully detected.
+*Note:* Automatic detection of the device type currently does not work with the Arduino Due because of issues with its Wire library. To work around this, specify the device and SA0 state manually (e.g. @init(LSM303::device_LSM303DLM, LSM303::sa0_high)@).
+- @byte getDeviceType(void)@ := Returns the device type detected by @init()@.
+- @void enableDefault(void)@ := Turns on the accelerometer and magnetometer and enables a consistent set of default settings.
+This function will set the accelerometer's full scale to be +/-2 g, which means that a reading of 16384 corresponds to approximately 1 g. The magnetometer's full scale is set to +/-4 gauss for the LSM303D or +/-1.3 gauss on all other devices. See the comments in LSM303.cpp for a full explanation of these settings.
+- @void writeReg(regAddr reg, byte value)@ := Writes an accelerometer or magnetometer register with the given value. Register addresses are defined by the regAddr enumeration type in LSM303.h.
+Example use: @compass.writeReg(LSM303::CTRL_REG1_A, 0x57);@
+- @void readReg(regAddr reg)@ := Reads an accelerometer or magnetometer register and returns the value read.[2]
+- @void writeAccReg(regAddr reg, byte value)@ := Writes an accelerometer register with the given value.
+- @byte readAccReg(regAddr reg)@ := Reads an accelerometer register and returns the value read.
+- @void writeMagReg(regAddr reg, byte value)@ := Writes a magnetometer register with the given value.
+- @byte readMagReg(regAddr reg)@ := Reads a magnetometer register and returns the value read. If the magnetometer data registers are read using register address constants without a specific device prefix (e.g. @OUT_Y_H_M@), this function will automatically use the correct register addresses depending on the device type.
+- @void readAcc(void)@ := Takes a reading from the accelerometer and stores the values in the vector @a@. Conversion of the readings to units of g depends on the accelerometer's selected gain (full scale setting).
+Note that in the LSM303DLHC, LSM303DLM, and LSM303DLH, the acceleration data registers actually contain a left-aligned 12-bit number, so the lowest 4 bits are always 0, and the values in @a@ should be shifted right by 4 bits (divided by 16) to be consistent with the conversion factors specified in the datasheets.
+- @void readMag(void)@ := Takes a reading from the magnetometer and stores the values in the vector @m@. Conversion of the readings to units of gauss depends on the magnetometer's selected gain (full scale setting).
+- @void read(void)@ := Takes a reading from both the accelerometer and magnetometer and stores the values in the vectors @a@ and @m@.
+- @void setTimeout(unsigned int timeout)@ := Sets a timeout period for @readAcc()@ and @readMag()@, in milliseconds, after which they will abort if no data is received. A value of 0 disables the timeout.
+- @unsigned int getTimeout(void)@ := Returns the current timeout period setting.
+- @bool timeoutOccurred(void)@ := Returns a boolean indicating whether a call to @readAcc()@ or @readMag()@ has timed out since the last call to @timeoutOccurred()@.
+- @float heading(void)@ := Returns the tilt-compensated heading of a default vector in degrees (the angular difference in the horizontal plane between the default vector and north). The default vector is chosen to point along the surface of the PCB, in the direction of the top of the text on the silkscreen. This is the +X axis on the Pololu LSM303D carrier and the -Y axis on the Pololu LSM303DLHC, LSM303DLM, and LSM303DLH carriers.
+- @float heading(vector from)@ := Returns the tilt-compensated heading of the given vector in degrees (the angular difference in the horizontal plane between @from@ and north).
+
+fn1. The automatic detection might fail if you do not use the Pololu boards' default accelerometer address, so you should specify your particular device if you change the state of the SA0 pin.
+
+fn2. This function will not work for reading TEMP_OUT_H_M and TEMP_OUT_L_M on the LSM303DLHC. To read those two registers, use @readMagReg()@ instead.
+
+h2. Version History
+
+* 2.0.0 (2013-11-27): Major rewrite. List of significant changes:
+** Added support for LSM303D.
+** Lowest 4 bits of accelerometer readings are no longer dropped before being stored in @a@; this makes the values returned by the library more consistent between the LSM303D and older sensors.
+** @enableDefault()@ behavior changed to be more consistent across devices.
+** @heading()@ now returns a float instead of an int.
+** Library constants converted to enums.
+** Added @writeReg()@ and @readReg()@, which should be usable in place of @writeAccReg()@, @readAccReg()@, @writeMagReg()@, and @readMagReg()@ in most situations.
+** @timeoutOccurred()@ now reports whether a timeout occurred since it was last called instead of only on the most recent @readAcc()@ or @readMag()@ call.
+** Magnetometer gain functions removed; unfortunately, they would have been hard to update to support the LSM303D.
+* 1.4.4 (2013-07-22): Corrected comments explaining @heading()@ function.
+* 1.4.3 (2013-03-15): Enable high resolution mode for LSM303DLHC accelerometer in @enableDefault()@.
+* 1.4.2 (2012-10-31): Cast sensor readings to 16-bit ints for better portability.
+* 1.4.1 (2012-07-06): Added @getDeviceType()@ function for programs that need to autodetect devices and distinguish between them.
+* 1.4.0 (2012-05-24): Added magnetometer gain functions and reading timeout feature; thanks to Joshua Hogendorn and Eric Brundick for these contributions. Added keywords.txt and changed file extensions of examples to .ino.
+* 1.3.0 (2011-12-12): Arduino 1.0 compatibility.
+* 1.2.0 (2011-11-15): Original release. (numbered to avoid confusion with our earlier "LSM303DLH library":https://github.com/pololu/LSM303DLH)
+** Besides the name change, the main difference in this library is that you need to call the @init()@ function before using any of the other library functions, typically from within the Arduino @setup()@ function. While the older library only works with the Pololu boards' default accelerometer slave address of 0011000b, this library allows you to specify the slave address with the @init()@ function.
Index: trunk/Arduino/GSM/libraries/LSM303/examples/Calibrate/Calibrate.ino
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/examples/Calibrate/Calibrate.ino	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/examples/Calibrate/Calibrate.ino	(revision 17969)
@@ -0,0 +1,33 @@
+#include <Wire.h>
+#include <LSM303.h>
+
+LSM303 compass;
+LSM303::vector<int16_t> running_min = {32767, 32767, 32767}, running_max = {-32768, -32768, -32768};
+
+char report[80];
+
+void setup() {
+  Serial.begin(9600);
+  Wire.begin();
+  compass.init();
+  compass.enableDefault();
+}
+
+void loop() {  
+  compass.read();
+  
+  running_min.x = min(running_min.x, compass.m.x);
+  running_min.y = min(running_min.y, compass.m.y);
+  running_min.z = min(running_min.z, compass.m.z);
+
+  running_max.x = max(running_max.x, compass.m.x);
+  running_max.y = max(running_max.y, compass.m.y);
+  running_max.z = max(running_max.z, compass.m.z);
+  
+  snprintf(report, sizeof(report), "min: {%+6d, %+6d, %+6d}    max: {%+6d, %+6d, %+6d}",
+    running_min.x, running_min.y, running_min.z,
+    running_max.x, running_max.y, running_max.z);
+  Serial.println(report);
+  
+  delay(100);
+}
Index: trunk/Arduino/GSM/libraries/LSM303/examples/Heading/Heading.ino
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/examples/Heading/Heading.ino	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/examples/Heading/Heading.ino	(revision 17969)
@@ -0,0 +1,46 @@
+#include <Wire.h>
+#include <LSM303.h>
+
+LSM303 compass;
+
+void setup() {
+  Serial.begin(9600);
+  Wire.begin();
+  compass.init();
+  compass.enableDefault();
+  
+  /*
+  Calibration values; the default values of +/-32767 for each axis
+  lead to an assumed magnetometer bias of 0. Use the Calibrate example
+  program to determine appropriate values for your particular unit.
+  */
+  compass.m_min = (LSM303::vector<int16_t>){-32767, -32767, -32767};
+  compass.m_max = (LSM303::vector<int16_t>){+32767, +32767, +32767};
+}
+
+void loop() {
+  compass.read();
+  
+  /*
+  When given no arguments, the heading() function returns the angular
+  difference in the horizontal plane between a default vector and
+  north, in degrees.
+  
+  The default vector is chosen by the library to point along the
+  surface of the PCB, in the direction of the top of the text on the
+  silkscreen. This is the +X axis on the Pololu LSM303D carrier and
+  the -Y axis on the Pololu LSM303DLHC, LSM303DLM, and LSM303DLH
+  carriers.
+  
+  To use a different vector as a reference, use the version of heading()
+  that takes a vector argument; for example, use
+  
+    compass.heading((LSM303::vector<int>){0, 0, 1});
+  
+  to use the +Z axis as a reference.
+  */
+  float heading = compass.heading();
+  
+  Serial.println(heading);
+  delay(100);
+}
Index: trunk/Arduino/GSM/libraries/LSM303/examples/Serial/Serial.ino
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/examples/Serial/Serial.ino	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/examples/Serial/Serial.ino	(revision 17969)
@@ -0,0 +1,54 @@
+/*
+The sensor outputs provided by the library are the raw 16-bit values
+obtained by concatenating the 8-bit high and low accelerometer and
+magnetometer data registers. They can be converted to units of g and
+gauss using the conversion factors specified in the datasheet for your
+particular device and full scale setting (gain).
+
+Example: An LSM303D gives a magnetometer X axis reading of 1982 with
+its default full scale setting of +/- 4 gauss. The M_GN specification
+in the LSM303D datasheet (page 10) states a conversion factor of 0.160
+mgauss/LSB (least significant bit) at this FS setting, so the raw
+reading of -1982 corresponds to 1982 * 0.160 = 317.1 mgauss =
+0.3171 gauss.
+
+In the LSM303DLHC, LSM303DLM, and LSM303DLH, the acceleration data
+registers actually contain a left-aligned 12-bit number, so the lowest
+4 bits are always 0, and the values should be shifted right by 4 bits
+(divided by 16) to be consistent with the conversion factors specified
+in the datasheets.
+
+Example: An LSM303DLH gives an accelerometer Z axis reading of -16144
+with its default full scale setting of +/- 2 g. Dropping the lowest 4
+bits gives a 12-bit raw value of -1009. The LA_So specification in the
+LSM303DLH datasheet (page 11) states a conversion factor of 1 mg/digit
+at this FS setting, so the value of -1009 corresponds to -1009 * 1 =
+1009 mg = 1.009 g.
+*/
+
+#include <Wire.h>
+#include <LSM303.h>
+
+LSM303 compass;
+
+char report[80];
+
+void setup()
+{
+  Serial.begin(9600);
+  Wire.begin();
+  compass.init();
+  compass.enableDefault();
+}
+
+void loop()
+{
+  compass.read();
+
+  snprintf(report, sizeof(report), "A: %6d %6d %6d    M: %6d %6d %6d",
+    compass.a.x, compass.a.y, compass.a.z,
+    compass.m.x, compass.m.y, compass.m.z);
+  Serial.println(report);
+
+  delay(100);
+}
Index: trunk/Arduino/GSM/libraries/LSM303/keywords.txt
===================================================================
--- trunk/Arduino/GSM/libraries/LSM303/keywords.txt	(revision 17969)
+++ trunk/Arduino/GSM/libraries/LSM303/keywords.txt	(revision 17969)
@@ -0,0 +1,145 @@
+LSM303	KEYWORD1
+
+init	KEYWORD2
+getDeviceType	KEYWORD2
+enableDefault	KEYWORD2
+writeAccReg	KEYWORD2
+readAccReg	KEYWORD2
+writeMagReg	KEYWORD2
+readMagReg	KEYWORD2
+writeReg	KEYWORD2
+readReg	KEYWORD2
+readAcc	KEYWORD2
+readMag	KEYWORD2
+read	KEYWORD2
+setTimeout	KEYWORD2
+getTimeout	KEYWORD2
+timeoutOccurred	KEYWORD2
+heading	KEYWORD2
+vector_cross	KEYWORD2
+vector_dot	KEYWORD2
+vector_normalize	KEYWORD2
+
+device_DLH	LITERAL1
+device_DLM	LITERAL1
+device_DLHC	LITERAL1
+device_D	LITERAL1
+device_auto	LITERAL1
+sa0_low	LITERAL1
+sa0_high	LITERAL1
+sa0_auto	LITERAL1
+TEMP_OUT_L	LITERAL1
+TEMP_OUT_H	LITERAL1
+STATUS_M	LITERAL1
+INT_CTRL_M	LITERAL1
+INT_SRC_M	LITERAL1
+INT_THS_L_M	LITERAL1
+INT_THS_H_M	LITERAL1
+OFFSET_X_L_M	LITERAL1
+OFFSET_X_H_M	LITERAL1
+OFFSET_Y_L_M	LITERAL1
+OFFSET_Y_H_M	LITERAL1
+OFFSET_Z_L_M	LITERAL1
+OFFSET_Z_H_M	LITERAL1
+REFERENCE_X	LITERAL1
+REFERENCE_Y	LITERAL1
+REFERENCE_Z	LITERAL1
+CTRL0	LITERAL1
+CTRL1	LITERAL1
+CTRL_REG1_A	LITERAL1
+CTRL2	LITERAL1
+CTRL_REG2_A	LITERAL1
+CTRL3	LITERAL1
+CTRL_REG3_A	LITERAL1
+CTRL4	LITERAL1
+CTRL_REG4_A	LITERAL1
+CTRL5	LITERAL1
+CTRL_REG5_A	LITERAL1
+CTRL6	LITERAL1
+CTRL_REG6_A	LITERAL1
+HP_FILTER_RESET_A	LITERAL1
+CTRL7	LITERAL1
+REFERENCE_A	LITERAL1
+STATUS_A	LITERAL1
+STATUS_REG_A	LITERAL1
+OUT_X_L_A	LITERAL1
+OUT_X_H_A	LITERAL1
+OUT_Y_L_A	LITERAL1
+OUT_Y_H_A	LITERAL1
+OUT_Z_L_A	LITERAL1
+OUT_Z_H_A	LITERAL1
+FIFO_CTRL	LITERAL1
+FIFO_CTRL_REG_A	LITERAL1
+FIFO_SRC	LITERAL1
+FIFO_SRC_REG_A	LITERAL1
+IG_CFG1	LITERAL1
+INT1_CFG_A	LITERAL1
+IG_SRC1	LITERAL1
+INT1_SRC_A	LITERAL1
+IG_THS1	LITERAL1
+INT1_THS_A	LITERAL1
+IG_DUR1	LITERAL1
+INT1_DURATION_A	LITERAL1
+IG_CFG2	LITERAL1
+INT2_CFG_A	LITERAL1
+IG_SRC2	LITERAL1
+INT2_SRC_A	LITERAL1
+IG_THS2	LITERAL1
+INT2_THS_A	LITERAL1
+IG_DUR2	LITERAL1
+INT2_DURATION_A	LITERAL1
+CLICK_CFG	LITERAL1
+CLICK_CFG_A	LITERAL1
+CLICK_SRC	LITERAL1
+CLICK_SRC_A	LITERAL1
+CLICK_THS	LITERAL1
+CLICK_THS_A	LITERAL1
+TIME_LIMIT	LITERAL1
+TIME_LIMIT_A	LITERAL1
+TIME_LATENCY	LITERAL1
+TIME_LATENCY_A	LITERAL1
+TIME_WINDOW	LITERAL1
+TIME_WINDOW_A	LITERAL1
+Act_THS	LITERAL1
+Act_DUR	LITERAL1
+CRA_REG_M	LITERAL1
+CRB_REG_M	LITERAL1
+MR_REG_M	LITERAL1
+SR_REG_M	LITERAL1
+IRA_REG_M	LITERAL1
+IRB_REG_M	LITERAL1
+IRC_REG_M	LITERAL1
+WHO_AM_I_M	LITERAL1
+WHO_AM_I	LITERAL1
+TEMP_OUT_H_M	LITERAL1
+TEMP_OUT_L_M	LITERAL1
+OUT_X_H_M	LITERAL1
+OUT_X_L_M	LITERAL1
+OUT_Y_H_M	LITERAL1
+OUT_Y_L_M	LITERAL1
+OUT_Z_H_M	LITERAL1
+OUT_Z_L_M	LITERAL1
+DLH_OUT_X_H_M	LITERAL1
+DLH_OUT_X_L_M	LITERAL1
+DLH_OUT_Y_H_M	LITERAL1
+DLH_OUT_Y_L_M	LITERAL1
+DLH_OUT_Z_H_M	LITERAL1
+DLH_OUT_Z_L_M	LITERAL1
+DLM_OUT_X_H_M	LITERAL1
+DLM_OUT_X_L_M	LITERAL1
+DLM_OUT_Z_H_M	LITERAL1
+DLM_OUT_Z_L_M	LITERAL1
+DLM_OUT_Y_H_M	LITERAL1
+DLM_OUT_Y_L_M	LITERAL1
+DLHC_OUT_X_H_M	LITERAL1
+DLHC_OUT_X_L_M	LITERAL1
+DLHC_OUT_Z_H_M	LITERAL1
+DLHC_OUT_Z_L_M	LITERAL1
+DLHC_OUT_Y_H_M	LITERAL1
+DLHC_OUT_Y_L_M	LITERAL1
+D_OUT_X_L_M	LITERAL1
+D_OUT_X_H_M	LITERAL1
+D_OUT_Y_L_M	LITERAL1
+D_OUT_Y_H_M	LITERAL1
+D_OUT_Z_L_M	LITERAL1
+D_OUT_Z_H_M	LITERAL1
Index: trunk/Arduino/GSM/libraries/readme.txt
===================================================================
--- trunk/Arduino/GSM/libraries/readme.txt	(revision 17969)
+++ trunk/Arduino/GSM/libraries/readme.txt	(revision 17969)
@@ -0,0 +1,1 @@
+For information on installing libraries, see: http://arduino.cc/en/Guide/Libraries
