source: trunk/FACT++/src/agilentctrl.cc@ 14299

Last change on this file since 14299 was 14299, checked in by neise, 12 years ago
just need to check in quickly
File size: 13.8 KB
Line 
1#include <functional>
2
3#include "Dim.h"
4#include "Event.h"
5#include "Shell.h"
6#include "StateMachineDim.h"
7#include "Connection.h"
8#include "LocalControl.h"
9#include "Configuration.h"
10#include "Console.h"
11#include "Converter.h"
12
13#include "tools.h"
14
15#include "HeadersAgilent.h"
16
17namespace ba = boost::asio;
18namespace bs = boost::system;
19namespace dummy = ba::placeholders;
20
21using namespace std;
22using namespace Agilent;
23
24// ------------------------------------------------------------------------
25
26class ConnectionAgilent : public Connection
27{
28 boost::asio::streambuf fBuffer;
29
30 bool fIsVerbose;
31 bool fDump;
32
33 ofstream fDumpStream;
34
35protected:
36
37
38 void Dump(const string &str)
39 {
40 if (!fDumpStream.is_open())
41 {
42 fDumpStream.open("socket_dump-agilent.txt", ios::app);
43 if (!fDumpStream)
44 {
45 //ostringstream str;
46 //str << "Open file " << name << ": " << strerror(errno) << " (errno=" << errno << ")";
47 //Error(str);
48
49 return;
50 }
51 }
52
53 fDumpStream << str << endl;
54 }
55
56private:
57
58
59 void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int /*type*/)
60 {
61 // Do not schedule a new read if the connection failed.
62 if (bytes_received==0 || err)
63 {
64 if (err==ba::error::eof)
65 Warn("Connection closed by remote host (FTM).");
66
67 // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
68 // 125: Operation canceled
69 if (err && err!=ba::error::eof && // Connection closed by remote host
70 err!=ba::error::basic_errors::not_connected && // Connection closed by remote host
71 err!=ba::error::basic_errors::operation_aborted) // Connection closed by us
72 {
73 ostringstream str;
74 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
75 Error(str);
76 }
77 PostClose(err!=ba::error::basic_errors::operation_aborted);
78 return;
79 }
80
81 if (fIsVerbose)
82 Out() << kBold << "Received (" << bytes_received << " bytes):" << endl;
83
84
85 if (fDump)
86 {
87 ostringstream msg;
88 msg << "--- " << Time().GetAsStr() << " --- received " << bytes_received << " bytes.";
89 Dump(msg.str());
90 }
91
92
93 istream is(&fBuffer);
94
95// int status=-1;
96
97 string buffer;
98 while (getline(is, buffer, '\n'))
99 {
100 if (fIsVerbose)
101 Out() << buffer << endl;
102 if (fDump)
103 Dump(buffer);
104
105 buffer = Tools::Trim(buffer);
106
107 if (buffer.empty())
108 continue;
109
110/*
111 istringstream in(buffer);
112 while (1)
113 {
114 float f;
115 in >> f;
116 if (!in)
117 break;
118
119 resist.push_back(f);
120 }
121*/
122 }
123
124 vector<float> voltages;
125 vector<float> currents;
126
127
128/*
129 if (fIsVerbose)
130 {
131 for (size_t i=0; i<resist.size(); i++)
132 if (resist[i]>800 && resist[i]<2000)
133 Out() << setw(2) << i << " - " << setw(4) << (int)resist[i] << ": " << setprecision(1) << fixed << GetTempPT1000(resist[i]) << endl;
134 else
135 Out() << setw(2) << i << " - " << setw(4) << (int)resist[i] << ": " << "----" << endl;
136 }
137*/
138 UpdateVolt(time, voltages);
139 UpdateCur( time, currents);
140
141 StartRead();
142 }
143
144 void StartRead()
145 {
146 ba::async_read_until(*this, fBuffer, "\n",
147 boost::bind(&ConnectionAgilent::HandleReceivedData, this,
148 dummy::error, dummy::bytes_transferred, 0));
149
150 // FIXME: Add timeout here
151 }
152
153 // This is called when a connection was established
154 void ConnectionEstablished()
155 {
156 fBuffer.prepare(10000);
157 StartRead();
158 }
159
160public:
161 ConnectionAgilent(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
162 fIsVerbose(true),
163 fDump(true)
164 {
165 SetLogStream(&imp);
166 }
167
168 void SetVerbose(bool b)
169 {
170 fIsVerbose = b;
171 }
172
173 void SetDumpStream(bool b)
174 {
175 fDump = b;
176 }
177
178 void SetOutput(bool b)
179 {
180 if (b)
181 {
182 PostMessage("outp on\n");
183 }
184 else
185 {
186 PostMessage("outp off\n");
187 }
188 }
189
190 void Identify()
191 {
192 PostMessage("*IDN?\n",6);
193 PostMessage("meas:volt?\n",11);
194 PostMessage("meas:curr?\n",11);
195 }
196};
197
198// ------------------------------------------------------------------------
199
200#include "DimDescriptionService.h"
201
202class ConnectionDimAgilent : public ConnectionAgilent
203{
204private:
205
206 DimDescribedService fDim;
207
208 void Update(DimDescribedService &svc, vector<float> data) const
209 {
210 svc.Update(data);
211 }
212
213 void UpdateDim(const vector<float> &data)
214 {
215 Update(fDim, data);
216 }
217
218
219public:
220 ConnectionDimAgilent(ba::io_service& ioservice, MessageImp &imp) :
221 ConnectionAgilent(ioservice, imp),
222 fDim("AGILENT_CONTROL/DATA", "F:1;F:1",
223 "|U[V]: FACT supply voltage"
224 "|I[A]: current consumed by the FACT camera")
225 {
226 // nothing happens here.
227 }
228};
229
230// ------------------------------------------------------------------------
231
232template <class T, class S>
233class StateMachineAgilent : public T, public ba::io_service, public ba::io_service::work
234{
235private:
236 S fAgilent;
237
238 int Disconnect()
239 {
240 // Close all connections
241 fAgilent.PostClose(false);
242
243 /*
244 // Now wait until all connection have been closed and
245 // all pending handlers have been processed
246 poll();
247 */
248
249 return T::GetCurrentState();
250 }
251
252 int Reconnect(const EventImp &evt)
253 {
254 // Close all connections to supress the warning in SetEndpoint
255 fAgilent.PostClose(false);
256
257 // Now wait until all connection have been closed and
258 // all pending handlers have been processed
259 poll();
260
261 if (evt.GetBool())
262 fAgilent.SetEndpoint(evt.GetString());
263
264 // Now we can reopen the connection
265 fAgilent.PostClose(true);
266
267 return T::GetCurrentState();
268 }
269
270 int Execute()
271 {
272 // Dispatch (execute) at most one handler from the queue. In contrary
273 // to run_one(), it doesn't wait until a handler is available
274 // which can be dispatched, so poll_one() might return with 0
275 // handlers dispatched. The handlers are always dispatched/executed
276 // synchronously, i.e. within the call to poll_one()
277 poll_one();
278
279 return fAgilent.IsConnected() ? State::kConnected : State::kDisconnected;
280 }
281
282 bool CheckEventSize(size_t has, const char *name, size_t size)
283 {
284 if (has==size)
285 return true;
286
287 ostringstream msg;
288 msg << name << " - Received event has " << has << " bytes, but expected " << size << ".";
289 T::Fatal(msg);
290 return false;
291 }
292
293 int SetVerbosity(const EventImp &evt)
294 {
295 if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
296 return T::kSM_FatalError;
297
298 fAgilent.SetVerbose(evt.GetBool());
299
300 return T::GetCurrentState();
301 }
302
303 int SetDumpStream(const EventImp &evt)
304 {
305 if (!CheckEventSize(evt.GetSize(), "SetDumpStream", 1))
306 return T::kSM_FatalError;
307
308 fAgilent.SetDumpStream(evt.GetBool());
309
310 return T::GetCurrentState();
311 }
312
313 int SetOutput(const EventImp &evt)
314 {
315 if (!CheckEventSize(evt.GetSize(), "SetOutput", 1))
316 return T::kSM_FatalError;
317
318 fAgilent.SetOutput(evt.GetBool());
319
320 return T::GetCurrentState();
321 }
322
323 int Identify()
324 {
325 fAgilent.Identify();
326 return T::GetCurrentState();
327 }
328
329public:
330 StateMachineAgilent(ostream &out=cout) :
331 T(out, "AGILENT_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
332 fAgilent(*this, *this)
333 {
334 // ba::io_service::work is a kind of keep_alive for the loop.
335 // It prevents the io_service to go to stopped state, which
336 // would prevent any consecutive calls to run()
337 // or poll() to do nothing. reset() could also revoke to the
338 // previous state but this might introduce some overhead of
339 // deletion and creation of threads and more.
340
341 // State names
342 T::AddStateName(State::kDisconnected, "Disconnected",
343 "Agilent not connected via ethernet.");
344
345 T::AddStateName(State::kConnected, "Connected",
346 "Ethernet connection to Agilent established.");
347
348 // Verbosity commands
349 T::AddEvent("SET_VERBOSE", "B:1")
350 (bind(&StateMachineAgilent::SetVerbosity, this, placeholders::_1))
351 ("set verbosity state"
352 "|verbosity[bool]:disable or enable verbosity for received data (yes/no)");
353
354 T::AddEvent("DUMP_STREAM", "B:1")
355 (bind(&StateMachineAgilent::SetDumpStream, this, placeholders::_1))
356 (""
357 "");
358
359 // Conenction commands
360 T::AddEvent("DISCONNECT", State::kConnected)
361 (bind(&StateMachineAgilent::Disconnect, this))
362 ("disconnect from ethernet");
363
364 T::AddEvent("RECONNECT", "O", State::kDisconnected, State::kConnected)
365 (bind(&StateMachineAgilent::Reconnect, this, placeholders::_1))
366 ("(Re)connect ethernet connection to Agilent, a new address can be given"
367 "|[host][string]:new ethernet address in the form <host:port>");
368
369 T::AddEvent("OUTPUT", "B:1")
370 (bind(&StateMachineAgilent::SetOutput, this, placeholders::_1))
371 ("set output on or off"
372 "|[state][boolean]: output setting (1;0 or 'on';'off')");
373
374 T::AddEvent("IDENTIFY")
375 (bind(&StateMachineAgilent::Identify, this))
376 ("Request Agilent ID");
377
378 fAgilent.StartConnect();
379 }
380
381 void SetEndpoint(const string &url)
382 {
383 fAgilent.SetEndpoint(url);
384 }
385
386 int EvalOptions(Configuration &conf)
387 {
388 fAgilent.SetVerbose(!conf.Get<bool>("quiet"));
389
390 SetEndpoint(conf.Get<string>("addr"));
391
392 return -1;
393 }
394};
395
396// ------------------------------------------------------------------------
397
398#include "Main.h"
399
400template<class T, class S, class R>
401int RunShell(Configuration &conf)
402{
403 return Main::execute<T, StateMachineAgilent<S, R>>(conf);
404}
405
406void SetupConfiguration(Configuration &conf)
407{
408 po::options_description control("agilent_ctrl control options");
409 control.add_options()
410 ("no-dim", po_bool(), "Disable dim services")
411// ("addr,a", var<string>("localhost:8080"), "network address of Agilent")
412 ("addr,a", var<string>("10.0.100.220:5025"), "network address of Agilent")
413 ("quiet,q", po_bool(true), "Disable printing contents of all received messages (except dynamic data) in clear text.")
414 ;
415
416 conf.AddOptions(control);
417}
418
419/*
420 Extract usage clause(s) [if any] for SYNOPSIS.
421 Translators: "Usage" and "or" here are patterns (regular expressions) which
422 are used to match the usage synopsis in program output. An example from cp
423 (GNU coreutils) which contains both strings:
424 Usage: cp [OPTION]... [-T] SOURCE DEST
425 or: cp [OPTION]... SOURCE... DIRECTORY
426 or: cp [OPTION]... -t DIRECTORY SOURCE...
427 */
428void PrintUsage()
429{
430 cout <<
431 "The ftmctrl controls the FSC (FACT Slow Control) board.\n"
432 "\n"
433 "The default is that the program is started without user intercation. "
434 "All actions are supposed to arrive as DimCommands. Using the -c "
435 "option, a local shell can be initialized. With h or help a short "
436 "help message about the usuage can be brought to the screen.\n"
437 "\n"
438 "Usage: fscctrl [-c type] [OPTIONS]\n"
439 " or: fscctrl [OPTIONS]\n";
440 cout << endl;
441}
442
443void PrintHelp()
444{
445 Main::PrintHelp<StateMachineAgilent<StateMachine, ConnectionAgilent>>();
446
447 /* Additional help text which is printed after the configuration
448 options goes here */
449
450 /*
451 cout << "bla bla bla" << endl << endl;
452 cout << endl;
453 cout << "Environment:" << endl;
454 cout << "environment" << endl;
455 cout << endl;
456 cout << "Examples:" << endl;
457 cout << "test exam" << endl;
458 cout << endl;
459 cout << "Files:" << endl;
460 cout << "files" << endl;
461 cout << endl;
462 */
463}
464
465int main(int argc, const char* argv[])
466{
467 Configuration conf(argv[0]);
468 conf.SetPrintUsage(PrintUsage);
469 Main::SetupConfiguration(conf);
470 SetupConfiguration(conf);
471
472 if (!conf.DoParse(argc, argv, PrintHelp))
473 return 127;
474
475 //try
476 {
477 // No console access at all
478 if (!conf.Has("console"))
479 {
480 if (conf.Get<bool>("no-dim"))
481 return RunShell<LocalStream, StateMachine, ConnectionAgilent>(conf);
482 else
483 return RunShell<LocalStream, StateMachineDim, ConnectionDimAgilent>(conf);
484 }
485 // Cosole access w/ and w/o Dim
486 if (conf.Get<bool>("no-dim"))
487 {
488 if (conf.Get<int>("console")==0)
489 return RunShell<LocalShell, StateMachine, ConnectionAgilent>(conf);
490 else
491 return RunShell<LocalConsole, StateMachine, ConnectionAgilent>(conf);
492 }
493 else
494 {
495 if (conf.Get<int>("console")==0)
496 return RunShell<LocalShell, StateMachineDim, ConnectionDimAgilent>(conf);
497 else
498 return RunShell<LocalConsole, StateMachineDim, ConnectionDimAgilent>(conf);
499 }
500 }
501 /*catch (std::exception& e)
502 {
503 cerr << "Exception: " << e.what() << endl;
504 return -1;
505 }*/
506
507 return 0;
508}
Note: See TracBrowser for help on using the repository browser.