| 1 | #include <boost/algorithm/string.hpp>
 | 
|---|
| 2 | 
 | 
|---|
| 3 | #include "FACT.h"
 | 
|---|
| 4 | #include "Dim.h"
 | 
|---|
| 5 | #include "Event.h"
 | 
|---|
| 6 | #include "StateMachineDim.h"
 | 
|---|
| 7 | #include "StateMachineAsio.h"
 | 
|---|
| 8 | #include "Connection.h"
 | 
|---|
| 9 | #include "LocalControl.h"
 | 
|---|
| 10 | #include "Configuration.h"
 | 
|---|
| 11 | #include "Console.h"
 | 
|---|
| 12 | 
 | 
|---|
| 13 | #include "tools.h"
 | 
|---|
| 14 | 
 | 
|---|
| 15 | #include "HeadersSQM.h"
 | 
|---|
| 16 | 
 | 
|---|
| 17 | namespace ba = boost::asio;
 | 
|---|
| 18 | namespace bs = boost::system;
 | 
|---|
| 19 | namespace dummy = ba::placeholders;
 | 
|---|
| 20 | 
 | 
|---|
| 21 | using namespace std;
 | 
|---|
| 22 | 
 | 
|---|
| 23 | class ConnectionSQM : public Connection
 | 
|---|
| 24 | {
 | 
|---|
| 25 | protected:
 | 
|---|
| 26 |     virtual void Update(const SQM::Data &)
 | 
|---|
| 27 |     {
 | 
|---|
| 28 |     }
 | 
|---|
| 29 | 
 | 
|---|
| 30 | private:
 | 
|---|
| 31 |     bool     fIsVerbose;
 | 
|---|
| 32 |     uint16_t fTimeout;
 | 
|---|
| 33 | 
 | 
|---|
| 34 |     boost::asio::streambuf fBuffer;
 | 
|---|
| 35 | 
 | 
|---|
| 36 |     boost::asio::deadline_timer fTrigger;
 | 
|---|
| 37 | 
 | 
|---|
| 38 |     void HandleRead(const boost::system::error_code& err, size_t bytes_received)
 | 
|---|
| 39 |     {
 | 
|---|
| 40 |         // Do not schedule a new read if the connection failed.
 | 
|---|
| 41 |         if (bytes_received==0 || err)
 | 
|---|
| 42 |         {
 | 
|---|
| 43 |             if (err==ba::error::eof)
 | 
|---|
| 44 |                 Warn("Connection closed by remote host.");
 | 
|---|
| 45 | 
 | 
|---|
| 46 |             // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
 | 
|---|
| 47 |             // 125: Operation canceled
 | 
|---|
| 48 |             if (err && err!=ba::error::eof &&                     // Connection closed by remote host
 | 
|---|
| 49 |                 err!=ba::error::basic_errors::not_connected &&    // Connection closed by remote host
 | 
|---|
| 50 |                 err!=ba::error::basic_errors::operation_aborted)  // Connection closed by us
 | 
|---|
| 51 |             {
 | 
|---|
| 52 |                 ostringstream str;
 | 
|---|
| 53 |                 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
 | 
|---|
| 54 |                 Error(str);
 | 
|---|
| 55 |             }
 | 
|---|
| 56 |             PostClose(err!=ba::error::basic_errors::operation_aborted);
 | 
|---|
| 57 |             return;
 | 
|---|
| 58 |         }
 | 
|---|
| 59 | 
 | 
|---|
| 60 |         istream is(&fBuffer);
 | 
|---|
| 61 | 
 | 
|---|
| 62 |         string buffer;
 | 
|---|
| 63 |         if (!getline(is, buffer, '\n'))
 | 
|---|
| 64 |         {
 | 
|---|
| 65 |             Fatal("Received message does not contain \\n... closing connection.");
 | 
|---|
| 66 |             PostClose(false);
 | 
|---|
| 67 |             return;
 | 
|---|
| 68 |         }
 | 
|---|
| 69 | 
 | 
|---|
| 70 |         buffer = buffer.substr(0, buffer.size()-1);
 | 
|---|
| 71 | 
 | 
|---|
| 72 |         if (fIsVerbose)
 | 
|---|
| 73 |             Out() << Time().GetAsStr("%H:%M:%S.%f") << "[" << buffer.size() << "]: " << buffer << endl;
 | 
|---|
| 74 | 
 | 
|---|
| 75 |         vector<string> vec;
 | 
|---|
| 76 |         boost::split(vec, buffer, boost::is_any_of(","));
 | 
|---|
| 77 | 
 | 
|---|
| 78 |         // Send next request in fTimeout milliseconds calculated from
 | 
|---|
| 79 |         // the last request onwards.
 | 
|---|
| 80 |         fTrigger.expires_at(fTrigger.expires_at()+boost::posix_time::milliseconds(fTimeout));
 | 
|---|
| 81 |         fTrigger.async_wait(boost::bind(&ConnectionSQM::HandleRequestTrigger,
 | 
|---|
| 82 |                                           this, dummy::error));
 | 
|---|
| 83 |         try
 | 
|---|
| 84 |         {
 | 
|---|
| 85 |             if (vec.size()!=6)
 | 
|---|
| 86 |                 throw runtime_error("Unknown number of fields in received data");
 | 
|---|
| 87 | 
 | 
|---|
| 88 |             if (vec[0]!="r")
 | 
|---|
| 89 |                 throw runtime_error("Not a 'reading request' answer: "+vec[0]);
 | 
|---|
| 90 | 
 | 
|---|
| 91 |             SQM::Data data;
 | 
|---|
| 92 | 
 | 
|---|
| 93 |             data.mag    = stof(vec[1]);
 | 
|---|
| 94 |             data.freq   = stol(vec[2]);
 | 
|---|
| 95 |             data.counts = stol(vec[3]);
 | 
|---|
| 96 |             data.period = stof(vec[4]);
 | 
|---|
| 97 |             data.temp   = stof(vec[5]);
 | 
|---|
| 98 | 
 | 
|---|
| 99 |             Update(data);
 | 
|---|
| 100 |         }
 | 
|---|
| 101 |         catch (const exception &e)
 | 
|---|
| 102 |         {
 | 
|---|
| 103 |             Error("Parsing received data failed ["+string(e.what())+"]");
 | 
|---|
| 104 |             Error("Received: "+buffer);
 | 
|---|
| 105 |             PostClose(true);
 | 
|---|
| 106 |         }
 | 
|---|
| 107 |     }
 | 
|---|
| 108 | 
 | 
|---|
| 109 |     void HandleReadTimeout(const bs::error_code &error)
 | 
|---|
| 110 |     {
 | 
|---|
| 111 |         // 125: Operation canceled (bs::error_code(125, bs::system_category))
 | 
|---|
| 112 |         if (error && error!=ba::error::basic_errors::operation_aborted)
 | 
|---|
| 113 |         {
 | 
|---|
| 114 |             ostringstream str;
 | 
|---|
| 115 |             str << "ReadTimeout of " << URL() << " failed: " << error.message() << " (" << error << ")";// << endl;
 | 
|---|
| 116 |             Error(str);
 | 
|---|
| 117 | 
 | 
|---|
| 118 |             PostClose(true);
 | 
|---|
| 119 |             return;
 | 
|---|
| 120 |         }
 | 
|---|
| 121 | 
 | 
|---|
| 122 |         if (!is_open())
 | 
|---|
| 123 |         {
 | 
|---|
| 124 |             // For example: Here we could schedule a new accept if we
 | 
|---|
| 125 |             // would not want to allow two connections at the same time.
 | 
|---|
| 126 |             //PostClose(true);
 | 
|---|
| 127 |             return;
 | 
|---|
| 128 |         }
 | 
|---|
| 129 | 
 | 
|---|
| 130 |         // Check whether the deadline has passed. We compare the deadline
 | 
|---|
| 131 |         // against the current time since a new asynchronous operation
 | 
|---|
| 132 |         // may have moved the deadline before this actor had a chance
 | 
|---|
| 133 |         // to run.
 | 
|---|
| 134 |         if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
 | 
|---|
| 135 |             return;
 | 
|---|
| 136 | 
 | 
|---|
| 137 |         ostringstream str;
 | 
|---|
| 138 |         str << "No valid answer received from " << URL() << " within " << ceil(fTimeout*1.5) << "ms";
 | 
|---|
| 139 |         Error(str);
 | 
|---|
| 140 | 
 | 
|---|
| 141 |         PostClose(true);
 | 
|---|
| 142 |     }
 | 
|---|
| 143 | 
 | 
|---|
| 144 |     void HandleRequestTrigger(const bs::error_code &error)
 | 
|---|
| 145 |     {
 | 
|---|
| 146 |         // 125: Operation canceled (bs::error_code(125, bs::system_category))
 | 
|---|
| 147 |         if (error && error!=ba::error::basic_errors::operation_aborted)
 | 
|---|
| 148 |         {
 | 
|---|
| 149 |             ostringstream str;
 | 
|---|
| 150 |             str << "RequestTrigger failed of " << URL() << " failed: " << error.message() << " (" << error << ")";// << endl;
 | 
|---|
| 151 |             Error(str);
 | 
|---|
| 152 | 
 | 
|---|
| 153 |             PostClose(true);
 | 
|---|
| 154 |             return;
 | 
|---|
| 155 |         }
 | 
|---|
| 156 | 
 | 
|---|
| 157 |         if (!is_open())
 | 
|---|
| 158 |         {
 | 
|---|
| 159 |             // For example: Here we could schedule a new accept if we
 | 
|---|
| 160 |             // would not want to allow two connections at the same time.
 | 
|---|
| 161 |             //PostClose(true);
 | 
|---|
| 162 |             return;
 | 
|---|
| 163 |         }
 | 
|---|
| 164 | 
 | 
|---|
| 165 |         // Check whether the deadline has passed. We compare the deadline
 | 
|---|
| 166 |         // against the current time since a new asynchronous operation
 | 
|---|
| 167 |         // may have moved the deadline before this actor had a chance
 | 
|---|
| 168 |         // to run.
 | 
|---|
| 169 |         if (fTrigger.expires_at() > ba::deadline_timer::traits_type::now())
 | 
|---|
| 170 |             return;
 | 
|---|
| 171 | 
 | 
|---|
| 172 |         StartReadReport();
 | 
|---|
| 173 |     }
 | 
|---|
| 174 | 
 | 
|---|
| 175 |     void StartReadReport()
 | 
|---|
| 176 |     {
 | 
|---|
| 177 |         PostMessage(string("rx\n"), 3);
 | 
|---|
| 178 | 
 | 
|---|
| 179 |         async_read_until(*this, fBuffer, '\n',
 | 
|---|
| 180 |                          boost::bind(&ConnectionSQM::HandleRead, this,
 | 
|---|
| 181 |                                      dummy::error, dummy::bytes_transferred));
 | 
|---|
| 182 | 
 | 
|---|
| 183 |         fInTimeout.expires_from_now(boost::posix_time::milliseconds(fTimeout*1.5));
 | 
|---|
| 184 |         fInTimeout.async_wait(boost::bind(&ConnectionSQM::HandleReadTimeout,
 | 
|---|
| 185 |                                           this, dummy::error));
 | 
|---|
| 186 |     }
 | 
|---|
| 187 | 
 | 
|---|
| 188 | private:
 | 
|---|
| 189 |     // This is called when a connection was established
 | 
|---|
| 190 |     void ConnectionEstablished()
 | 
|---|
| 191 |     {
 | 
|---|
| 192 |         StartReadReport();
 | 
|---|
| 193 |         fTrigger.expires_at(Time());
 | 
|---|
| 194 |     }
 | 
|---|
| 195 | 
 | 
|---|
| 196 | public:
 | 
|---|
| 197 |     static const uint16_t kMaxAddr;
 | 
|---|
| 198 | 
 | 
|---|
| 199 | public:
 | 
|---|
| 200 |     ConnectionSQM(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
 | 
|---|
| 201 |         fIsVerbose(true), fTimeout(0), fTrigger(ioservice)
 | 
|---|
| 202 |     {
 | 
|---|
| 203 |         SetLogStream(&imp);
 | 
|---|
| 204 |     }
 | 
|---|
| 205 | 
 | 
|---|
| 206 |     void SetVerbose(bool b)
 | 
|---|
| 207 |     {
 | 
|---|
| 208 |         fIsVerbose = b;
 | 
|---|
| 209 |         Connection::SetVerbose(b);
 | 
|---|
| 210 |     }
 | 
|---|
| 211 | 
 | 
|---|
| 212 |     void SetTimeout(uint16_t t)
 | 
|---|
| 213 |     {
 | 
|---|
| 214 |         fTimeout = t;
 | 
|---|
| 215 |     }
 | 
|---|
| 216 | 
 | 
|---|
| 217 |     int GetState() const
 | 
|---|
| 218 |     {
 | 
|---|
| 219 |         return is_open() ? SQM::State::kConnected : SQM::State::kDisconnected;
 | 
|---|
| 220 |     }
 | 
|---|
| 221 | };
 | 
|---|
| 222 | 
 | 
|---|
| 223 | // ------------------------------------------------------------------------
 | 
|---|
| 224 | 
 | 
|---|
| 225 | #include "DimDescriptionService.h"
 | 
|---|
| 226 | 
 | 
|---|
| 227 | class ConnectionDimWeather : public ConnectionSQM
 | 
|---|
| 228 | {
 | 
|---|
| 229 | private:
 | 
|---|
| 230 |     DimDescribedService fDim;
 | 
|---|
| 231 | 
 | 
|---|
| 232 | public:
 | 
|---|
| 233 |     ConnectionDimWeather(ba::io_service& ioservice, MessageImp &imp) :
 | 
|---|
| 234 |         ConnectionSQM(ioservice, imp),
 | 
|---|
| 235 |         fDim("SQM_CONTROL/DATA", "F:1;I:1;I:1;F:1;F:1",
 | 
|---|
| 236 |              "Data received from sky quality meter"
 | 
|---|
| 237 |              "|mag[mag/arcsec^2]:Magnitude (0 means upper brightness limit)"
 | 
|---|
| 238 |              "|freq[Hz]:Frequency of sensor"
 | 
|---|
| 239 |              "|counts:Period of sensor (counts occur at 14.7456MHz/32)"
 | 
|---|
| 240 |              "|period[s]:Period of sensor"
 | 
|---|
| 241 |              "|temp[deg C]:Sensor temperature in deg C")
 | 
|---|
| 242 |     {
 | 
|---|
| 243 |     }
 | 
|---|
| 244 | 
 | 
|---|
| 245 |     void Update(const SQM::Data &data)
 | 
|---|
| 246 |     {
 | 
|---|
| 247 |         fDim.Update(data);
 | 
|---|
| 248 |     }
 | 
|---|
| 249 | };
 | 
|---|
| 250 | 
 | 
|---|
| 251 | // ------------------------------------------------------------------------
 | 
|---|
| 252 | 
 | 
|---|
| 253 | template <class T, class S>
 | 
|---|
| 254 | class StateMachineSQMControl : public StateMachineAsio<T>
 | 
|---|
| 255 | {
 | 
|---|
| 256 | private:
 | 
|---|
| 257 |     S fSQM;
 | 
|---|
| 258 | 
 | 
|---|
| 259 |     bool CheckEventSize(size_t has, const char *name, size_t size)
 | 
|---|
| 260 |     {
 | 
|---|
| 261 |         if (has==size)
 | 
|---|
| 262 |             return true;
 | 
|---|
| 263 | 
 | 
|---|
| 264 |         ostringstream msg;
 | 
|---|
| 265 |         msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
 | 
|---|
| 266 |         T::Fatal(msg);
 | 
|---|
| 267 |         return false;
 | 
|---|
| 268 |     }
 | 
|---|
| 269 | 
 | 
|---|
| 270 |     int Disconnect()
 | 
|---|
| 271 |     {
 | 
|---|
| 272 |         // Close all connections
 | 
|---|
| 273 |         fSQM.PostClose(false);
 | 
|---|
| 274 | 
 | 
|---|
| 275 |         return T::GetCurrentState();
 | 
|---|
| 276 |     }
 | 
|---|
| 277 | 
 | 
|---|
| 278 |     int Reconnect(const EventImp &evt)
 | 
|---|
| 279 |     {
 | 
|---|
| 280 |         // Close all connections to supress the warning in SetEndpoint
 | 
|---|
| 281 |         fSQM.PostClose(false);
 | 
|---|
| 282 | 
 | 
|---|
| 283 |         // Now wait until all connection have been closed and
 | 
|---|
| 284 |         // all pending handlers have been processed
 | 
|---|
| 285 |         ba::io_service::poll();
 | 
|---|
| 286 | 
 | 
|---|
| 287 |         if (evt.GetBool())
 | 
|---|
| 288 |             fSQM.SetEndpoint(evt.GetString());
 | 
|---|
| 289 | 
 | 
|---|
| 290 |         // Now we can reopen the connection
 | 
|---|
| 291 |         fSQM.PostClose(true);
 | 
|---|
| 292 | 
 | 
|---|
| 293 |         return T::GetCurrentState();
 | 
|---|
| 294 |     }
 | 
|---|
| 295 | 
 | 
|---|
| 296 |     int SetVerbosity(const EventImp &evt)
 | 
|---|
| 297 |     {
 | 
|---|
| 298 |         if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
 | 
|---|
| 299 |             return T::kSM_FatalError;
 | 
|---|
| 300 | 
 | 
|---|
| 301 |         fSQM.SetVerbose(evt.GetBool());
 | 
|---|
| 302 | 
 | 
|---|
| 303 |         return T::GetCurrentState();
 | 
|---|
| 304 |     }
 | 
|---|
| 305 | 
 | 
|---|
| 306 |     int Send(const string &cmd)
 | 
|---|
| 307 |     {
 | 
|---|
| 308 |         const string tx = cmd+"\r\n";
 | 
|---|
| 309 |         fSQM.PostMessage(tx, tx.size());
 | 
|---|
| 310 |         return T::GetCurrentState();
 | 
|---|
| 311 |     }
 | 
|---|
| 312 | 
 | 
|---|
| 313 |     int SendCommand(const EventImp &evt)
 | 
|---|
| 314 |     {
 | 
|---|
| 315 |         return Send(evt.GetString());
 | 
|---|
| 316 |     }
 | 
|---|
| 317 | 
 | 
|---|
| 318 |     int Execute()
 | 
|---|
| 319 |     {
 | 
|---|
| 320 |         return fSQM.GetState();
 | 
|---|
| 321 |     }
 | 
|---|
| 322 | 
 | 
|---|
| 323 | 
 | 
|---|
| 324 | public:
 | 
|---|
| 325 |     StateMachineSQMControl(ostream &out=cout) :
 | 
|---|
| 326 |         StateMachineAsio<T>(out, "SQM_CONTROL"), fSQM(*this, *this)
 | 
|---|
| 327 |     {
 | 
|---|
| 328 |         // State names
 | 
|---|
| 329 |         T::AddStateName(SQM::State::kDisconnected, "Disconnected",
 | 
|---|
| 330 |                         "No connection to Sky Quality Meter");
 | 
|---|
| 331 | 
 | 
|---|
| 332 |         T::AddStateName(SQM::State::kConnected, "Connected",
 | 
|---|
| 333 |                         "Connection established, but no valid message received");
 | 
|---|
| 334 | 
 | 
|---|
| 335 |         T::AddStateName(SQM::State::kValid, "Valid",
 | 
|---|
| 336 |                         "Valid message received");
 | 
|---|
| 337 | 
 | 
|---|
| 338 |         // Commands
 | 
|---|
| 339 |         //T::AddEvent("SEND_COMMAND", "C")
 | 
|---|
| 340 |         //    (bind(&StateMachineSQMControl::SendCommand, this, placeholders::_1))
 | 
|---|
| 341 |         //    ("Send command to SQM");
 | 
|---|
| 342 | 
 | 
|---|
| 343 |         // Verbosity commands
 | 
|---|
| 344 |         T::AddEvent("SET_VERBOSE", "B")
 | 
|---|
| 345 |             (bind(&StateMachineSQMControl::SetVerbosity, this, placeholders::_1))
 | 
|---|
| 346 |             ("set verbosity state"
 | 
|---|
| 347 |              "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
 | 
|---|
| 348 | 
 | 
|---|
| 349 |         //T::AddEvent("ENABLE")
 | 
|---|
| 350 |         //    (bind(&StateMachineSQMControl::Send, this, "veto_60"))
 | 
|---|
| 351 |         //    ("Enable trigger signal once a second vetoed at every exact minute");
 | 
|---|
| 352 | 
 | 
|---|
| 353 |         //T::AddEvent("DISABLE")
 | 
|---|
| 354 |         //    (bind(&StateMachineSQMControl::Send, this, "veto_on"))
 | 
|---|
| 355 |         //    ("Diable trigger output");
 | 
|---|
| 356 | 
 | 
|---|
| 357 |         // Conenction commands
 | 
|---|
| 358 |         T::AddEvent("DISCONNECT")
 | 
|---|
| 359 |             (bind(&StateMachineSQMControl::Disconnect, this))
 | 
|---|
| 360 |             ("disconnect from ethernet");
 | 
|---|
| 361 | 
 | 
|---|
| 362 |          T::AddEvent("RECONNECT", "O")
 | 
|---|
| 363 |             (bind(&StateMachineSQMControl::Reconnect, this, placeholders::_1))
 | 
|---|
| 364 |             ("(Re)connect ethernet connection to SQM, a new address can be given"
 | 
|---|
| 365 |              "|[host][string]:new ethernet address in the form <host:port>");
 | 
|---|
| 366 | 
 | 
|---|
| 367 |     }
 | 
|---|
| 368 | 
 | 
|---|
| 369 |     int EvalOptions(Configuration &conf)
 | 
|---|
| 370 |     {
 | 
|---|
| 371 |         fSQM.SetVerbose(!conf.Get<bool>("quiet"));
 | 
|---|
| 372 |         fSQM.SetTimeout(conf.Get<uint16_t>("request-interval"));
 | 
|---|
| 373 |         fSQM.SetDebugTx(conf.Get<bool>("debug-tx"));
 | 
|---|
| 374 |         fSQM.SetEndpoint(conf.Get<string>("addr"));
 | 
|---|
| 375 |         fSQM.StartConnect();
 | 
|---|
| 376 | 
 | 
|---|
| 377 |         return -1;
 | 
|---|
| 378 |     }
 | 
|---|
| 379 | };
 | 
|---|
| 380 | 
 | 
|---|
| 381 | // ------------------------------------------------------------------------
 | 
|---|
| 382 | 
 | 
|---|
| 383 | #include "Main.h"
 | 
|---|
| 384 | 
 | 
|---|
| 385 | 
 | 
|---|
| 386 | template<class T, class S, class R>
 | 
|---|
| 387 | int RunShell(Configuration &conf)
 | 
|---|
| 388 | {
 | 
|---|
| 389 |     return Main::execute<T, StateMachineSQMControl<S, R>>(conf);
 | 
|---|
| 390 | }
 | 
|---|
| 391 | 
 | 
|---|
| 392 | void SetupConfiguration(Configuration &conf)
 | 
|---|
| 393 | {
 | 
|---|
| 394 |     po::options_description control("SQM control");
 | 
|---|
| 395 |     control.add_options()
 | 
|---|
| 396 |         ("no-dim,d",         po_switch(),         "Disable dim services")
 | 
|---|
| 397 |         ("addr,a",           var<string>("10.0.100.208:10001"), "Network address of the lid controling Arduino including port")
 | 
|---|
| 398 |         ("quiet,q",          po_bool(true),       "Disable printing contents of all received messages (except dynamic data) in clear text.")
 | 
|---|
| 399 |         ("debug-tx",         po_bool(),           "Enable debugging of ethernet transmission.")
 | 
|---|
| 400 |         ("request-interval", var<uint16_t>(5000), "How often to request a report [milliseconds].")
 | 
|---|
| 401 |         ;
 | 
|---|
| 402 | 
 | 
|---|
| 403 |     conf.AddOptions(control);
 | 
|---|
| 404 | }
 | 
|---|
| 405 | 
 | 
|---|
| 406 | /*
 | 
|---|
| 407 |  Extract usage clause(s) [if any] for SYNOPSIS.
 | 
|---|
| 408 |  Translators: "Usage" and "or" here are patterns (regular expressions) which
 | 
|---|
| 409 |  are used to match the usage synopsis in program output.  An example from cp
 | 
|---|
| 410 |  (GNU coreutils) which contains both strings:
 | 
|---|
| 411 |   Usage: cp [OPTION]... [-T] SOURCE DEST
 | 
|---|
| 412 |     or:  cp [OPTION]... SOURCE... DIRECTORY
 | 
|---|
| 413 |     or:  cp [OPTION]... -t DIRECTORY SOURCE...
 | 
|---|
| 414 |  */
 | 
|---|
| 415 | void PrintUsage()
 | 
|---|
| 416 | {
 | 
|---|
| 417 |     cout <<
 | 
|---|
| 418 |         "The sqmctrl is an interface to the Sky Quality Meter.\n"
 | 
|---|
| 419 |         "\n"
 | 
|---|
| 420 |         "The default is that the program is started without user intercation. "
 | 
|---|
| 421 |         "All actions are supposed to arrive as DimCommands. Using the -c "
 | 
|---|
| 422 |         "option, a local shell can be initialized. With h or help a short "
 | 
|---|
| 423 |         "help message about the usuage can be brought to the screen.\n"
 | 
|---|
| 424 |         "\n"
 | 
|---|
| 425 |         "Usage: sqmctrl [-c type] [OPTIONS]\n"
 | 
|---|
| 426 |         "  or:  sqmctrl [OPTIONS]\n";
 | 
|---|
| 427 |     cout << endl;
 | 
|---|
| 428 | }
 | 
|---|
| 429 | 
 | 
|---|
| 430 | void PrintHelp()
 | 
|---|
| 431 | {
 | 
|---|
| 432 | //    Main::PrintHelp<StateMachineFTM<StateMachine, ConnectionFTM>>();
 | 
|---|
| 433 | 
 | 
|---|
| 434 |     /* Additional help text which is printed after the configuration
 | 
|---|
| 435 |      options goes here */
 | 
|---|
| 436 | 
 | 
|---|
| 437 |     /*
 | 
|---|
| 438 |      cout << "bla bla bla" << endl << endl;
 | 
|---|
| 439 |      cout << endl;
 | 
|---|
| 440 |      cout << "Environment:" << endl;
 | 
|---|
| 441 |      cout << "environment" << endl;
 | 
|---|
| 442 |      cout << endl;
 | 
|---|
| 443 |      cout << "Examples:" << endl;
 | 
|---|
| 444 |      cout << "test exam" << endl;
 | 
|---|
| 445 |      cout << endl;
 | 
|---|
| 446 |      cout << "Files:" << endl;
 | 
|---|
| 447 |      cout << "files" << endl;
 | 
|---|
| 448 |      cout << endl;
 | 
|---|
| 449 |      */
 | 
|---|
| 450 | }
 | 
|---|
| 451 | 
 | 
|---|
| 452 | int main(int argc, const char* argv[])
 | 
|---|
| 453 | {
 | 
|---|
| 454 |     Configuration conf(argv[0]);
 | 
|---|
| 455 |     conf.SetPrintUsage(PrintUsage);
 | 
|---|
| 456 |     Main::SetupConfiguration(conf);
 | 
|---|
| 457 |     SetupConfiguration(conf);
 | 
|---|
| 458 | 
 | 
|---|
| 459 |     if (!conf.DoParse(argc, argv, PrintHelp))
 | 
|---|
| 460 |         return 127;
 | 
|---|
| 461 | 
 | 
|---|
| 462 |     // No console access at all
 | 
|---|
| 463 |     if (!conf.Has("console"))
 | 
|---|
| 464 |     {
 | 
|---|
| 465 |         if (conf.Get<bool>("no-dim"))
 | 
|---|
| 466 |             return RunShell<LocalStream, StateMachine, ConnectionSQM>(conf);
 | 
|---|
| 467 |         else
 | 
|---|
| 468 |             return RunShell<LocalStream, StateMachineDim, ConnectionDimWeather>(conf);
 | 
|---|
| 469 |     }
 | 
|---|
| 470 |     // Cosole access w/ and w/o Dim
 | 
|---|
| 471 |     if (conf.Get<bool>("no-dim"))
 | 
|---|
| 472 |     {
 | 
|---|
| 473 |         if (conf.Get<int>("console")==0)
 | 
|---|
| 474 |             return RunShell<LocalShell, StateMachine, ConnectionSQM>(conf);
 | 
|---|
| 475 |         else
 | 
|---|
| 476 |             return RunShell<LocalConsole, StateMachine, ConnectionSQM>(conf);
 | 
|---|
| 477 |     }
 | 
|---|
| 478 |     else
 | 
|---|
| 479 |     {
 | 
|---|
| 480 |         if (conf.Get<int>("console")==0)
 | 
|---|
| 481 |             return RunShell<LocalShell, StateMachineDim, ConnectionDimWeather>(conf);
 | 
|---|
| 482 |         else
 | 
|---|
| 483 |             return RunShell<LocalConsole, StateMachineDim, ConnectionDimWeather>(conf);
 | 
|---|
| 484 |     }
 | 
|---|
| 485 | 
 | 
|---|
| 486 |     return 0;
 | 
|---|
| 487 | }
 | 
|---|