Changeset 51 in flair-src for trunk/lib/FlairSensorActuator
- Timestamp:
- Jul 26, 2016, 5:32:57 PM (8 years ago)
- Location:
- trunk/lib/FlairSensorActuator/src
- Files:
-
- 9 edited
- 2 moved
Legend:
- Unmodified
- Added
- Removed
-
trunk/lib/FlairSensorActuator/src/Imu.h
r15 r51 17 17 18 18 namespace flair { 19 namespace core {20 class ImuData;21 class OneAxisRotation;22 }23 namespace gui {24 class Tab;25 class TabWidget;26 class GroupBox;27 class Layout;28 class DataPlot1D;29 }19 namespace core { 20 class ImuData; 21 class OneAxisRotation; 22 } 23 namespace gui { 24 class Tab; 25 class TabWidget; 26 class GroupBox; 27 class Layout; 28 class DataPlot1D; 29 } 30 30 } 31 31 -
trunk/lib/FlairSensorActuator/src/Mb800.cpp
r42 r51 28 28 29 29 Mb800::Mb800(const FrameworkManager *parent, string name, 30 SerialPort *serialport, Gps::NMEAFlags_t NMEAFlags,30 SerialPort *serialport, NmeaGps::NMEAFlags_t NMEAFlags, 31 31 uint8_t priority) 32 : Gps(parent, name, NMEAFlags), Thread(parent, name, priority) {32 : NmeaGps(parent, name, NMEAFlags), Thread(parent, name, priority) { 33 33 this->serialport = serialport; 34 34 serialport->SetRxTimeout(100000000); -
trunk/lib/FlairSensorActuator/src/Mb800.h
r15 r51 15 15 16 16 #include <Thread.h> 17 #include < Gps.h>17 #include <NmeaGps.h> 18 18 19 19 namespace flair { … … 30 30 * \brief Class for mb800 gps receiver 31 31 */ 32 class Mb800 : public core::Thread, public Gps {32 class Mb800 : public core::Thread, public NmeaGps { 33 33 public: 34 34 /*! … … 44 44 */ 45 45 Mb800(const core::FrameworkManager *parent, std::string name, 46 core::SerialPort *serialport, Gps::NMEAFlags_t NMEAFlags,46 core::SerialPort *serialport, NmeaGps::NMEAFlags_t NMEAFlags, 47 47 uint8_t priority); 48 48 -
trunk/lib/FlairSensorActuator/src/NmeaGps.cpp
r42 r51 4 4 // %flair:license} 5 5 // created: 2013/08/23 6 // filename: Gps.cpp6 // filename: NmeaGps.cpp 7 7 // 8 8 // author: Guillaume Sanahuja … … 11 11 // version: $Id: $ 12 12 // 13 // purpose: objet integrant le recepteur gps mb80013 // purpose: Base class for GPS using NMEA sentances 14 14 // 15 15 // 16 16 /*********************************************************************/ 17 17 18 #include " Gps.h"18 #include "NmeaGps.h" 19 19 #include "geodesie.h" 20 20 #include <Euler.h> 21 #include <cvmatrix.h>22 21 #include <DataPlot1D.h> 23 22 #include <Tab.h> … … 31 30 #include <Vector3D.h> 32 31 #include <Label.h> 32 #include <GpsData.h> 33 33 #include <string.h> 34 34 … … 41 41 namespace sensor { 42 42 43 Gps::Gps(const FrameworkManager *parent, string name, NMEAFlags_t NMEAFlags)43 NmeaGps::NmeaGps(const FrameworkManager *parent, string name, NMEAFlags_t NMEAFlags) 44 44 : IODevice(parent, name) { 45 45 this->NMEAFlags = NMEAFlags; … … 50 50 51 51 if ((NMEAFlags & GGA) == 0) { 52 Err("Enable at least GGA sentence\n"); 53 } 54 55 int index = 0; 56 if ((NMEAFlags & GGA) != 0) { 57 index += 3; 58 } 59 if ((NMEAFlags & VTG) != 0) { 60 index += 2; 61 } 62 if ((NMEAFlags & GST) != 0) { 63 index += 3; 64 } 65 66 cvmatrix_descriptor *desc = new cvmatrix_descriptor(index, 1); 67 index = 0; 68 if ((NMEAFlags & GGA) != 0) { 69 desc->SetElementName(0, 0, "e"); 70 desc->SetElementName(1, 0, "n"); 71 desc->SetElementName(2, 0, "u"); 72 index += 3; 73 } 74 if ((NMEAFlags & VTG) != 0) { 75 desc->SetElementName(index, 0, "ve"); 76 desc->SetElementName(index + 1, 0, "vn"); 77 index += 2; 78 } 52 Err("Enable at least the GGA sentence\n"); 53 } 54 55 /* 79 56 if ((NMEAFlags & GST) != 0) { 80 57 desc->SetElementName(index, 0, "dev_lat"); … … 83 60 index += 3; 84 61 } 85 output = new cvmatrix((IODevice *)this, desc, floatType); 86 AddDataToLog(output); 62 */ 87 63 88 64 // station sol … … 97 73 position = new GeoCoordinate((IODevice *)this, "position", 0, 0, 0); 98 74 99 fix = FixQuality_t::Invalid;100 nb_sat = 0;101 75 take_ref = false; 102 nb_sat_label->SetText("nb_sat: %i", nb_sat); 103 fix_label->SetText("fix: %i", fix); 104 } 105 106 Gps::~Gps() { 76 77 gpsData = new GpsData(this); 78 AddDataToLog(gpsData); 79 80 nb_sat_label->SetText("nb_sat: %i", gpsData->GetNumberOfSatellites()); 81 fix_label->SetText("fix: %i", gpsData->GetFixQuality()); 82 } 83 84 NmeaGps::~NmeaGps() { 107 85 nmea_parser_destroy(&parser); 108 86 delete main_tab; 109 87 } 110 88 111 void Gps::UseDefaultPlot(void) { 112 int index = 0; 89 const GpsData *NmeaGps::GetDatas(void) const { 90 return gpsData; 91 } 92 93 void NmeaGps::GetDatas(core::GpsData **outGpsData) const { 94 *outGpsData = gpsData; 95 } 96 97 void NmeaGps::UseDefaultPlot(void) { 113 98 plot_tab = new Tab(tab, "Mesures"); 114 99 115 100 if ((NMEAFlags & GGA) != 0) { 116 101 e_plot = new DataPlot1D(plot_tab->NewRow(), "e", -10, 10); 117 e_plot->AddCurve( output->Element(index));102 e_plot->AddCurve(gpsData->Element(GpsData::East)); 118 103 n_plot = new DataPlot1D(plot_tab->LastRowLastCol(), "n", -10, 10); 119 n_plot->AddCurve( output->Element(index + 1));104 n_plot->AddCurve(gpsData->Element(GpsData::North)); 120 105 u_plot = new DataPlot1D(plot_tab->LastRowLastCol(), "u", -10, 10); 121 u_plot->AddCurve(output->Element(index + 2)); 122 index += 3; 106 u_plot->AddCurve(gpsData->Element(GpsData::Up)); 123 107 } 124 108 if ((NMEAFlags & VTG) != 0) { 125 109 ve_plot = new DataPlot1D(plot_tab->NewRow(), "ve", -10, 10); 126 ve_plot->AddCurve( output->Element(index));110 ve_plot->AddCurve(gpsData->Element(GpsData::EastVelocity)); 127 111 vn_plot = new DataPlot1D(plot_tab->LastRowLastCol(), "vn", -10, 10); 128 vn_plot->AddCurve(output->Element(index + 1)); 129 index += 2; 112 vn_plot->AddCurve(gpsData->Element(GpsData::NorthVelocity)); 130 113 } 131 114 … … 135 118 } 136 119 137 DataPlot1D * Gps::EPlot(void) const {120 DataPlot1D *NmeaGps::EPlot(void) const { 138 121 if ((NMEAFlags & GGA) != 0) { 139 122 return e_plot; … … 144 127 } 145 128 146 DataPlot1D * Gps::NPlot(void) const {129 DataPlot1D *NmeaGps::NPlot(void) const { 147 130 if ((NMEAFlags & GGA) != 0) { 148 131 return n_plot; … … 153 136 } 154 137 155 DataPlot1D * Gps::UPlot(void) const {138 DataPlot1D *NmeaGps::UPlot(void) const { 156 139 if ((NMEAFlags & GGA) != 0) { 157 140 return u_plot; … … 162 145 } 163 146 164 DataPlot1D * Gps::VEPlot(void) const {147 DataPlot1D *NmeaGps::VEPlot(void) const { 165 148 if ((NMEAFlags & VTG) != 0) { 166 149 return ve_plot; … … 171 154 } 172 155 173 DataPlot1D * Gps::VNPlot(void) const {156 DataPlot1D *NmeaGps::VNPlot(void) const { 174 157 if ((NMEAFlags & VTG) != 0) { 175 158 return vn_plot; … … 180 163 } 181 164 182 Layout *Gps::GetLayout(void) const { return sensor_tab; } 183 184 Tab *Gps::GetPlotTab(void) const { return plot_tab; } 185 186 TabWidget *Gps::GetTab(void) const { return tab; } 187 188 uint16_t Gps::NbSat(void) const { 189 output->GetMutex(); 190 uint16_t result = nb_sat; 191 output->ReleaseMutex(); 192 return result; 193 } 194 195 Gps::FixQuality_t Gps::FixQuality(void) const { 196 output->GetMutex(); 197 FixQuality_t result = fix; 198 output->ReleaseMutex(); 199 return result; 200 } 201 202 void Gps::SetRef(void) { take_ref = true; } 203 204 void Gps::GetENUPosition(Vector3D *point) { 205 output->GetMutex(); 206 point->x = output->ValueNoMutex(0, 0); 207 point->y = output->ValueNoMutex(1, 0); 208 point->z = output->ValueNoMutex(2, 0); 209 output->ReleaseMutex(); 210 } 211 212 void Gps::parseFrame(const char *frame, int frame_size) { 165 Layout *NmeaGps::GetLayout(void) const { return sensor_tab; } 166 167 Tab *NmeaGps::GetPlotTab(void) const { return plot_tab; } 168 169 TabWidget *NmeaGps::GetTab(void) const { return tab; } 170 171 void NmeaGps::SetRef(void) { take_ref = true; } 172 173 void NmeaGps::GetEnu(Vector3D *point) { 174 gpsData->GetMutex(); 175 gpsData->GetEnu(point->x,point->y,point->z); 176 gpsData->ReleaseMutex(); 177 } 178 179 void NmeaGps::parseFrame(const char *frame, int frame_size) { 213 180 214 181 int result; … … 222 189 223 190 if (result == 1) { 191 nmea_info2pos(&info, &pos); 224 192 // Printf("%s\n",frame); 225 // Printf("nb:%i fix:%i lat:%f long:%f alt:%f vel:%f226 // angle:%f\n",pack.satinuse,pack.sig,info.lat,info.lon,info.elv,info.speed*1000./3600.,info.direction);227 // Printf("lat:%f long:%f\n",pos.lat,pos.lon); 228 output->GetMutex(); // on utilise le mutex de l'outputpour fix et nb_sat229 if ( (int)fix !=pack.sig) {230 fix = (FixQuality_t)pack.sig;231 fix_label->SetText("fix: %i", fix);232 } 233 if ( nb_sat!= pack.satinuse) {234 nb_sat = pack.satinuse;235 nb_sat_label->SetText("nb_sat: %i", nb_sat);236 } 237 output->ReleaseMutex();238 239 nmea_info2pos(&info, &pos);193 // Printf("nb:%i fix:%i lat:%f long:%f alt:%f vel:%f angle:%f\n",pack.satinuse,pack.sig,info.lat,info.lon,info.elv,info.speed*1000./3600.,info.direction); 194 //Printf("lat:%f long:%f\n",pos.lat,pos.lon); 195 196 gpsData->GetMutex(); // on utilise le mutex de gpsData pour fix et nb_sat 197 if (gpsData->GetFixQuality() != (GpsData::FixQuality_t)pack.sig) { 198 gpsData->SetFixQuality((GpsData::FixQuality_t)pack.sig); 199 fix_label->SetText("fix: %i", pack.sig); 200 } 201 if (gpsData->GetNumberOfSatellites() != pack.satinuse) { 202 gpsData->SetNumberOfSatellites(pack.satinuse) ; 203 nb_sat_label->SetText("nb_sat: %i", pack.satinuse); 204 } 205 gpsData->ReleaseMutex(); 206 207 gpsData->SetLla(Euler::ToDegree(pos.lat), Euler::ToDegree(pos.lon),info.elv); 240 208 position->SetCoordinates(Euler::ToDegree(pos.lat), Euler::ToDegree(pos.lon), 241 209 info.elv); … … 257 225 // Printf("lon:%f lat:%f elv:%f\n",pos.lon,pos.lat,info.elv); 258 226 259 // on prend une fois pour toute le mutex et on fait des accès directs 260 output->GetMutex(); 261 output->SetValueNoMutex(0, 0, e); 262 output->SetValueNoMutex(1, 0, n); 263 output->SetValueNoMutex(2, 0, u); 264 265 int index = 3; 227 gpsData->SetEnu(e,n,u); 228 266 229 if ((NMEAFlags & VTG) != 0) { 267 output->SetValueNoMutex(index, 0, 268 info.speed * 1000. / 3600. * 269 sin(Euler::ToRadian(info.direction))); 270 output->SetValueNoMutex(index + 1, 0, 271 info.speed * 1000. / 3600. * 272 cos(Euler::ToRadian(info.direction))); 273 index += 2; 274 } 230 gpsData->SetVelocity(info.speed * 1000. / 3600. * sin(Euler::ToRadian(info.direction)), 231 info.speed * 1000. / 3600. * cos(Euler::ToRadian(info.direction))); 232 }/* 275 233 if ((NMEAFlags & GST) != 0) { 276 234 // Thread::Printf("dev_lon:%f dev_lat:%f … … 280 238 output->SetValueNoMutex(index + 2, 0, info.dev_elv); 281 239 index += 3; 282 } 283 output->ReleaseMutex(); 284 285 output->SetDataTime(GetTime());286 ProcessUpdate( output);240 }*/ 241 242 243 gpsData->SetDataTime(GetTime()); 244 ProcessUpdate(gpsData); 287 245 } 288 246 } -
trunk/lib/FlairSensorActuator/src/NmeaGps.h
r42 r51 4 4 // %flair:license} 5 5 /*! 6 * \file Gps.h7 * \brief Base class for GPS 6 * \file NmeaGps.h 7 * \brief Base class for GPS using NMEA sentances 8 8 * \author Guillaume Sanahuja, Copyright Heudiasyc UMR UTC/CNRS 7253 9 9 * \date 2013/08/23 … … 11 11 */ 12 12 13 #ifndef GPS_H14 #define GPS_H13 #ifndef NMEAGPS_H 14 #define NMEAGPS_H 15 15 16 16 #include <IODevice.h> … … 18 18 19 19 namespace flair { 20 namespace core {21 class cvmatrix;22 class FrameworkManager;23 class GeoCoordinate;24 class Vector3D;25 }26 namespace gui {27 class Layout;28 class DataPlot1D;29 class Tab;30 class TabWidget;31 class PushButton;32 class Map;33 class Label;34 }20 namespace core { 21 class FrameworkManager; 22 class GeoCoordinate; 23 class Vector3D; 24 class GpsData; 25 } 26 namespace gui { 27 class Layout; 28 class DataPlot1D; 29 class Tab; 30 class TabWidget; 31 class PushButton; 32 class Map; 33 class Label; 34 } 35 35 } 36 36 37 37 namespace flair { 38 38 namespace sensor { 39 /*! \class Gps 39 40 /*! \class NmeaGps 40 41 * 41 * \brief Base class for GPS 42 * \brief Base class for GPS using NMEA sentances 42 43 */ 43 class Gps : public core::IODevice {44 class NmeaGps : public core::IODevice { 44 45 public: 45 /*!46 \enum FixQuality_t47 \brief Fix qualty indicators48 */49 enum class FixQuality_t {50 Invalid = 0, /*!< invalid */51 Gps = 1, /*!< Gps */52 DGps = 2, /*!< Differential Gps */53 Pps = 3, /*!< Pps */54 Rtk = 4, /*!< RTK */55 RtkFloat = 5, /*!< RTK float */56 Estimated = 6, /*!< Estimated */57 Manual = 7, /*!< Manual */58 Simulation = 8, /*!< Simulation */59 };60 61 46 /*! 62 47 \enum NMEAFlags_t … … 72 57 * \brief Constructor 73 58 * 74 * Construct a Gps.59 * Construct a NmeaGps. 75 60 * 76 61 * \param parent parent … … 78 63 * \param NMEAFlags NMEA sentances to enable 79 64 */ 80 Gps(const core::FrameworkManager *parent, std::string name,65 NmeaGps(const core::FrameworkManager *parent, std::string name, 81 66 NMEAFlags_t NMEAFlags); 82 67 … … 85 70 * 86 71 */ 87 ~Gps(); 72 ~NmeaGps(); 73 74 /*! 75 * \brief Get GPS datas 76 * 77 * \return GpsData 78 */ 79 const core::GpsData *GetDatas(void) const; 88 80 89 81 /*! … … 148 140 */ 149 141 gui::Tab *GetPlotTab(void) const; 150 151 /*!152 * \brief Number of used satellites153 *154 * \return number of used satellites155 */156 uint16_t NbSat(void) const;157 158 /*!159 * \brief Fix Quality160 *161 * \return fix quality162 */163 FixQuality_t FixQuality(void) const;164 142 165 143 /*! … … 178 156 * \param point to store position 179 157 */ 180 void GetE NUPosition(core::Vector3D *point);158 void GetEnu(core::Vector3D *point); 181 159 182 160 protected: … … 197 175 protected: 198 176 core::GeoCoordinate *position; 177 178 /*! 179 * \brief Get GPS datas 180 * 181 * \param gpsData GPS datas 182 */ 183 void GetDatas(core::GpsData **gpsData) const; 199 184 200 185 private: … … 219 204 gui::Map *map; 220 205 gui::Label *nb_sat_label, *fix_label; 221 uint16_t nb_sat;222 FixQuality_t fix;223 206 bool take_ref; 224 207 nmeaINFO info; … … 227 210 nmeaPOS pos; 228 211 double lat_ref, long_ref, alt_ref; 229 230 // matrix 231 core::cvmatrix *output; 212 core::GpsData* gpsData; 232 213 }; 233 214 } // end namespace sensor 234 215 } // end namespace framewor 235 #endif // GPS_H216 #endif // NMEAGPS_H -
trunk/lib/FlairSensorActuator/src/Novatel.cpp
r15 r51 28 28 29 29 Novatel::Novatel(const FrameworkManager *parent, string name, 30 SerialPort *serialport, Gps::NMEAFlags_t NMEAFlags,30 SerialPort *serialport, NmeaGps::NMEAFlags_t NMEAFlags, 31 31 uint8_t priority) 32 : Gps(parent, name, NMEAFlags), Thread(parent, name, priority) {32 : NmeaGps(parent, name, NMEAFlags), Thread(parent, name, priority) { 33 33 this->serialport = serialport; 34 34 } -
trunk/lib/FlairSensorActuator/src/Novatel.h
r15 r51 15 15 16 16 #include <Thread.h> 17 #include < Gps.h>17 #include <NmeaGps.h> 18 18 19 19 namespace flair { … … 30 30 * \brief Class for Novatel gps receiver 31 31 */ 32 class Novatel : public core::Thread, public Gps {32 class Novatel : public core::Thread, public NmeaGps { 33 33 public: 34 34 /*! … … 44 44 */ 45 45 Novatel(const core::FrameworkManager *parent, std::string name, 46 core::SerialPort *serialport, Gps::NMEAFlags_t NMEAFlags,46 core::SerialPort *serialport, NmeaGps::NMEAFlags_t NMEAFlags, 47 47 uint8_t priority); 48 48 -
trunk/lib/FlairSensorActuator/src/SimuGps.cpp
r15 r51 20 20 #include <string.h> 21 21 #include <GeoCoordinate.h> 22 #include <GpsData.h> 22 23 23 24 using std::string; … … 28 29 29 30 SimuGps::SimuGps(const FrameworkManager *parent, string name, 30 Gps::NMEAFlags_t NMEAFlags, uint8_t priority)31 : Thread(parent, name, priority), Gps(parent, name, NMEAFlags) {}31 NmeaGps::NMEAFlags_t NMEAFlags, uint8_t priority) 32 : Thread(parent, name, priority), NmeaGps(parent, name, NMEAFlags) {} 32 33 33 34 SimuGps::~SimuGps() { … … 37 38 38 39 void SimuGps::Run(void) { 39 char response[200] = {0};40 int size, result;41 40 // double lat=0; 41 char buf[500]; 42 nmeaGPGGA gga; 43 nmeaGPVTG vtg; 42 44 SetPeriodMS(500); 43 45 WarnUponSwitches(true); 44 46 47 gga.sig=1; 48 gga.satinuse=2; 49 gga.lat=49.402313; 50 gga.lon=2.795463; 51 52 vtg.spn=1; 53 vtg.dir=0; 54 45 55 while (!ToBeStopped()) { 46 56 WaitPeriod(); 57 58 nmea_gen_GPGGA(buf,sizeof(buf),&gga); 59 parseFrame(buf,sizeof(buf)); 47 60 position->SetCoordinates(49.402313, 2.795463, 0); 48 61 // lat+=.5; -
trunk/lib/FlairSensorActuator/src/SimuGps.h
r15 r51 15 15 16 16 #include <Thread.h> 17 #include < Gps.h>17 #include <NmeaGps.h> 18 18 19 19 namespace flair { … … 29 29 * \brief Class for a simulation GPS 30 30 */ 31 class SimuGps : public core::Thread, public Gps {31 class SimuGps : public core::Thread, public NmeaGps { 32 32 public: 33 33 /*! … … 42 42 */ 43 43 SimuGps(const core::FrameworkManager *parent, std::string name, 44 Gps::NMEAFlags_t NMEAFlags, uint8_t priority);44 NmeaGps::NMEAFlags_t NMEAFlags, uint8_t priority); 45 45 46 46 /*! -
trunk/lib/FlairSensorActuator/src/Srf08.cpp
r15 r51 99 99 100 100 if (written < 0) { 101 Thread::Err("err eur rt_dev_write(%s)\n", strerror(-written));101 Thread::Err("error write i2c (%s)\n", strerror(-written)); 102 102 } else if (written != 2) { 103 Thread::Err("err eur rt_dev_write%i/2\n", written);103 Thread::Err("error write i2c %i/2\n", written); 104 104 } 105 105 } … … 120 120 if (written < 0) { 121 121 i2cport->ReleaseMutex(); 122 Thread::Err("err eur rt_dev_write(%s)\n", strerror(-written));122 Thread::Err("error write i2c (%s)\n", strerror(-written)); 123 123 nb_err++; 124 124 if (nb_err == 20) { 125 Thread::Err("err eur rt_dev_write(%s), too many errors\n",125 Thread::Err("error write i2c (%s), too many errors\n", 126 126 strerror(-written)); 127 127 return; … … 134 134 if (read < 0) { 135 135 if (read != -ETIMEDOUT) 136 Thread::Err("err eur rt_dev_read (%s) %i\n", strerror(-written), read);136 Thread::Err("error read i2c (%s) %i\n", strerror(-read), read); 137 137 nb_err++; 138 138 if (nb_err == 20) { 139 Thread::Err("err eur rt_dev_read(%s), too many errors\n",139 Thread::Err("error read i2c (%s), too many errors\n", 140 140 strerror(-written)); 141 141 return; … … 143 143 SleepMS(1); 144 144 } else if (read != 2) { 145 Thread::Err("err eur rt_dev_read%i/2\n", read);145 Thread::Err("error read i2c %i/2\n", read); 146 146 return; 147 147 } else if (read == 2) { … … 187 187 188 188 if (written < 0) { 189 Thread::Err("err eur rt_dev_write(%s)\n", strerror(-written));189 Thread::Err("error write i2c (%s)\n", strerror(-written)); 190 190 } else if (written != 2) { 191 Thread::Err("err eur rt_dev_write%i/2\n", written);191 Thread::Err("error write i2c %i/2\n", written); 192 192 } 193 193 } … … 211 211 212 212 if (written < 0) { 213 Thread::Err("err eur write(%s)\n", strerror(-written));213 Thread::Err("error write i2c (%s)\n", strerror(-written)); 214 214 } else if (written != 2) { 215 Thread::Err("err eur write%i/2\n", written);215 Thread::Err("error write i2c %i/2\n", written); 216 216 } 217 217 } -
trunk/lib/FlairSensorActuator/src/Srf08.h
r15 r51 40 40 * \brief Constructor 41 41 * 42 * Construct a S imuUs. Control part.42 * Construct a SRF08 sensor 43 43 * 44 44 * \param parent parent
Note:
See TracChangeset
for help on using the changeset viewer.