source: trunk/FACT++/src/ftm.cc@ 10532

Last change on this file since 10532 was 10517, checked in by tbretz, 14 years ago
Added first version (not documented at all) of the fake-ftm and the ftmctrl
File size: 20.1 KB
Line 
1#include <iostream>
2#include <string>
3#include <boost/asio.hpp>
4#include <boost/bind.hpp>
5#include <boost/lexical_cast.hpp>
6#include <boost/asio/deadline_timer.hpp>
7#include <boost/enable_shared_from_this.hpp>
8
9using boost::lexical_cast;
10
11#include "Time.h"
12#include "Converter.h"
13
14#include "HeadersFTM.h"
15
16using namespace std;
17using namespace FTM;
18
19namespace ba = boost::asio;
20namespace bs = boost::system;
21namespace dummy = ba::placeholders;
22
23using boost::lexical_cast;
24using ba::ip::tcp;
25
26int Port = 0;
27
28// ------------------------------------------------------------------------
29
30
31// ------------------------------------------------------------------------
32
33class tcp_connection : public ba::ip::tcp::socket, public boost::enable_shared_from_this<tcp_connection>
34{
35private:
36
37 double fStartTime;
38
39 void AsyncRead(ba::mutable_buffers_1 buffers)
40 {
41 ba::async_read(*this, buffers,
42 boost::bind(&tcp_connection::HandleReceivedData, shared_from_this(),
43 dummy::error, dummy::bytes_transferred));
44 }
45
46 void AsyncWrite(const ba::const_buffers_1 &buffers)
47 {
48 ba::async_write(*this, buffers,
49 boost::bind(&tcp_connection::HandleSentData, shared_from_this(),
50 dummy::error, dummy::bytes_transferred));
51 }
52 void AsyncWait(ba::deadline_timer &timer, int seconds,
53 void (tcp_connection::*handler)(const bs::error_code&))// const
54 {
55 timer.expires_from_now(boost::posix_time::seconds(seconds));
56 timer.async_wait(boost::bind(handler, shared_from_this(), dummy::error));
57 }
58
59 ba::deadline_timer deadline_;
60
61 ba::deadline_timer fTriggerDynData;
62
63 // The constructor is prvate to force the obtained pointer to be shared
64 tcp_connection(ba::io_service& ioservice) : ba::ip::tcp::socket(ioservice),
65 deadline_(ioservice), fTriggerDynData(ioservice)
66 {
67 deadline_.expires_at(boost::posix_time::pos_infin);
68
69 fHeader.fDelimiter=kDelimiterStart;
70 fHeader.fState=FTM::kFtmIdle;
71 fHeader.fBoardId=0xaffe;
72 fHeader.fFirmwareId=0x42;
73
74 fDelimiter = htons(kDelimiterEnd);
75
76 fStaticData.clear();
77
78 fStaticData.fCoincidencePhysics = 1;
79 fStaticData.fCoincidenceCalib = 40;
80 fStaticData.fWindowCalib = 1;
81 fStaticData.fWindowPhysics = 0;
82 fStaticData.fDelayTrigger = 21;
83 fStaticData.fDelayTimeMarker = 42;
84 fStaticData.fDeadTime = 84;
85
86 fStaticData.fClockConditioner[0] = 100;
87 fStaticData.fClockConditioner[1] = 1;
88 fStaticData.fClockConditioner[2] = 8;
89 fStaticData.fClockConditioner[3] = 9;
90 fStaticData.fClockConditioner[4] = 11;
91 fStaticData.fClockConditioner[5] = 13;
92 fStaticData.fClockConditioner[6] = 14;
93 fStaticData.fClockConditioner[7] = 15;
94
95 fStaticData.fTriggerSequence = 1 | (2<<5) | (3<<10);
96
97 fStaticData.fGeneralSettings =
98 FTM::StaticData::kTrigger |
99 FTM::StaticData::kLP1 |
100 FTM::StaticData::kPedestal;
101
102 fStaticData.fActiveFTU[0] = 0x3ff;
103 fStaticData.fActiveFTU[3] = 0x3ff;
104
105 for (int i=0; i<40; i++)
106 {
107 for (int p=0; p<4; p++)
108 fStaticData[i].fEnable[p] = 0x5555;
109
110 for (int p=0; p<5; p++)
111 fStaticData[i].fDAC[p] = (p+1)*10;
112
113 fStaticData[i].fPrescaling = 42;
114 }
115
116 for (unsigned long long i=0; i<40; i++)
117 {
118 fFtuList[i].fDNA = (i<<48)|(i<<32)|(i<<16)|i;
119 fFtuList[i].fPingAddr = i;
120 }
121 }
122
123 // Callback when writing was successfull or failed
124 void HandleSentData(const boost::system::error_code& error, size_t bytes_transferred)
125 {
126 cout << "Data sent: (transmitted=" << bytes_transferred << ") rc=" << error.message() << " (" << error << ")" << endl;
127 }
128
129 vector<uint16_t> fBufCommand;
130 vector<uint16_t> fBufHeader;
131 vector<uint16_t> fBufFtuList;
132 vector<uint16_t> fBufStaticData;
133 vector<uint16_t> fBufDynamicData;
134
135 vector<uint16_t> fCommand;
136 FTM::Header fHeader;
137 FTM::FtuList fFtuList;
138 FTM::StaticData fStaticData;
139 FTM::DynamicData fDynamicData;
140
141 //vector<uint16_t> fStaticData;
142
143 uint16_t fDelimiter;
144 uint16_t fBufRegister;
145
146 uint16_t fCounter;
147
148 bool fReportsDisabled;
149
150 void SendDynamicData()
151 {
152 if (fReportsDisabled)
153 return;
154
155 if (fHeader.fState == FTM::kFtmRunning)
156 fDynamicData.fOnTimeCounter = lrint(Time().UnixTime()-fStartTime);
157
158 fDynamicData.fTempSensor[0] = (23. + (6.*rand()/RAND_MAX-3))*10;
159 fDynamicData.fTempSensor[1] = (55. + (6.*rand()/RAND_MAX-3))*10;
160 fDynamicData.fTempSensor[2] = (39. + (6.*rand()/RAND_MAX-3))*10;
161 fDynamicData.fTempSensor[3] = (42. + (6.*rand()/RAND_MAX-3))*10;
162
163 for (int i=0; i<40; i++)
164 for (int p=0; p<4; p++)
165 fDynamicData[i].fRatePatch[p] = (1000 + (float(rand())/RAND_MAX-0.5)*25*p);
166
167 fHeader.fType=kDynamicData; // FtuList
168 fHeader.fDataSize=sizeof(FTM::DynamicData)/2+1;
169 fHeader.fTriggerCounter = fCounter++;
170 fHeader.fTimeStamp = lrint(Time().UnixTime());
171
172 fBufHeader = fHeader.HtoN();
173 fBufDynamicData = fDynamicData.HtoN();
174
175 AsyncWrite(ba::buffer(ba::const_buffer(&fBufHeader[0], fBufHeader.size()*2)));
176 AsyncWrite(ba::buffer(ba::const_buffer(&fBufDynamicData[0], sizeof(FTM::DynamicData))));
177 AsyncWrite(ba::buffer(ba::const_buffer(&fDelimiter, 2)));
178 }
179
180 void SendStaticData()
181 {
182 fHeader.fType=kStaticData; // FtuList
183 fHeader.fDataSize=sizeof(FTM::StaticData)/2+1;
184 fHeader.fTriggerCounter = fCounter++;
185 fHeader.fTimeStamp = lrint(Time().UnixTime());
186
187 for (int i=0; i<4; i++)
188 fFtuList.fActiveFTU[i] = fStaticData.fActiveFTU[i];
189
190 fBufHeader = fHeader.HtoN();
191 fBufStaticData = fStaticData.HtoN();
192
193 AsyncWrite(ba::buffer(ba::const_buffer(&fBufHeader[0], fBufHeader.size()*2)));
194 AsyncWrite(ba::buffer(ba::const_buffer(&fBufStaticData[0], fBufStaticData.size()*2)));
195 AsyncWrite(ba::buffer(ba::const_buffer(&fDelimiter, 2)));
196 }
197
198 void HandleReceivedData(const boost::system::error_code& error, size_t bytes_received)
199 {
200 // Do not schedule a new read if the connection failed.
201 if (bytes_received==0)
202 {
203 // Close the connection
204 close();
205 deadline_.cancel();
206 return;
207 }
208
209 // No command received yet
210 if (fCommand.size()==0)
211 {
212 transform(fBufCommand.begin(), fBufCommand.begin()+bytes_received/2,
213 fBufCommand.begin(), ntohs);
214
215 if (fBufCommand[0]!='@')
216 {
217 cout << "Inavlid command: 0x" << hex << fBufCommand[0] << dec << endl;
218 cout << "Received b=" << bytes_received << ": " << error.message() << " (" << error << ")" << endl;
219 cout << "Hex:" << Converter::GetHex<uint16_t>(&fBufCommand[0], bytes_received) << endl;
220 return;
221 }
222
223 switch (fBufCommand[1])
224 {
225 case kCmdToggleLed:
226 cout << "-> TOGGLE_LED" << endl;
227
228 fBufCommand.resize(5);
229 AsyncRead(ba::buffer(fBufCommand));
230 return;
231
232 case kCmdPing:
233 cout << "-> PING" << endl;
234
235 fHeader.fType=kFtuList; // FtuList
236 fHeader.fDataSize=sizeof(FTM::FtuList)/2+1;
237 fHeader.fTriggerCounter = fCounter++;
238 fHeader.fTimeStamp = lrint(Time().UnixTime());
239
240 fBufHeader = fHeader.HtoN();
241 fBufFtuList = fFtuList.HtoN();
242
243 AsyncWrite(ba::buffer(ba::const_buffer(&fBufHeader[0], fBufHeader.size()*2)));
244 AsyncWrite(ba::buffer(ba::const_buffer(&fBufFtuList[0], fBufFtuList.size()*2)));
245 AsyncWrite(ba::buffer(ba::const_buffer(&fDelimiter, 2)));
246
247 fBufCommand.resize(5);
248 AsyncRead(ba::buffer(fBufCommand));
249 return;
250
251 case kCmdRead: // kCmdRead
252 cout << "-> READ" << endl;
253 switch (fBufCommand[2])
254 {
255 case kReadStaticData:
256 cout << "-> STATIC" << endl;
257
258 SendStaticData();
259
260 fBufCommand.resize(5);
261 AsyncRead(ba::buffer(fBufCommand));
262
263 return;
264
265 case kReadDynamicData:
266 cout << "-> DYNAMIC" << endl;
267
268 SendDynamicData();
269
270 fBufCommand.resize(5);
271 AsyncRead(ba::buffer(fBufCommand));
272
273 return;
274
275 case kReadRegister:
276 fCommand = fBufCommand;
277 cout << "-> REGISTER" << endl;
278
279 fBufCommand.resize(1);
280 AsyncRead(ba::buffer(fBufCommand));
281 return;
282 }
283 break;
284
285
286 case kCmdWrite:
287 switch (fBufCommand[2])
288 {
289 case kWriteRegister:
290 fCommand = fBufCommand;
291 cout << "-> REGISTER" << endl;
292
293 fBufCommand.resize(2);
294 AsyncRead(ba::buffer(fBufCommand));
295 return;
296
297 case kWriteStaticData:
298 fCommand = fBufCommand;
299 cout << "-> STATIC DATA" << endl;
300
301 fBufCommand.resize(sizeof(StaticData)/2);
302 AsyncRead(ba::buffer(fBufCommand));
303 return;
304 }
305 break;
306
307 case kCmdDisableReports:
308 cout << "-> DISABLE REPORTS " << !fBufCommand[2] << endl;
309 fReportsDisabled = !fBufCommand[2];
310
311 fBufCommand.resize(5);
312 AsyncRead(ba::buffer(fBufCommand));
313 return;
314
315 case kCmdStartRun:
316 fHeader.fState = FTM::kFtmRunning;
317
318 fStartTime = Time().UnixTime();
319
320 fBufCommand.resize(5);
321 AsyncRead(ba::buffer(fBufCommand));
322 return;
323
324 case kCmdStopRun:
325 fHeader.fState = FTM::kFtmIdle;
326
327 fBufCommand.resize(5);
328 AsyncRead(ba::buffer(fBufCommand));
329 return;
330 }
331
332 cout << "Received b=" << bytes_received << ": " << error.message() << " (" << error << ")" << endl;
333 cout << "Hex:" << Converter::GetHex<uint16_t>(&fBufCommand[0], bytes_received) << endl;
334 return;
335 }
336
337 // Command data received
338
339 // Prepare reception of next command
340 switch (fCommand[1])
341 {
342 case kCmdRead: // kCmdRead
343 {
344 const uint16_t addr = ntohs(fBufCommand[0]);
345 const uint16_t val = reinterpret_cast<uint16_t*>(&fStaticData)[addr];
346
347 cout << "-> GET REGISTER[" << addr << "]=" << val << endl;
348
349 fHeader.fType=kRegister; // FtuList
350 fHeader.fDataSize=2;
351 fHeader.fTriggerCounter = fCounter++;
352 fHeader.fTimeStamp = lrint(Time().UnixTime());
353
354 fBufHeader = fHeader.HtoN();
355 fBufStaticData[addr] = htons(val);
356
357 AsyncWrite(ba::buffer(ba::const_buffer(&fBufHeader[0], fBufHeader.size()*2)));
358 AsyncWrite(ba::buffer(ba::const_buffer(&fBufStaticData[addr], 2)));
359 AsyncWrite(ba::buffer(ba::const_buffer(&fDelimiter, 2)));
360 break;
361 }
362
363 case kCmdWrite:
364 switch (fCommand[2])
365 {
366 case kWriteRegister:
367 {
368 const uint16_t addr = ntohs(fBufCommand[0]);
369 const uint16_t val = ntohs(fBufCommand[1]);
370
371 cout << "-> SET REGISTER[" << addr << "]=" << val << endl;
372
373 reinterpret_cast<uint16_t*>(&fStaticData)[addr] = val;
374 }
375 break;
376
377 case kWriteStaticData:
378 {
379 cout << "-> SET STATIC DATA" << endl;
380 fStaticData = fBufCommand;
381 }
382 break;
383 }
384 break;
385 }
386
387 fCommand.resize(0);
388
389 fBufCommand.resize(5);
390 AsyncRead(ba::buffer(fBufCommand));
391 }
392
393 void check_deadline(const boost::system::error_code &)
394 {
395 if (!is_open())
396 {
397 // For example: Here we could schedule a new accept if we
398 // would not want to allow two connections at the same time.
399 return;
400 }
401
402 // Check whether the deadline has passed. We compare the deadline
403 // against the current time since a new asynchronous operation
404 // may have moved the deadline before this actor had a chance
405 // to run.
406 if (deadline_.expires_at() <= ba::deadline_timer::traits_type::now())
407 {
408 // The deadline has passed. Stop the session. The other
409 // actors will terminate as soon as possible.
410// AsyncWrite(ba::buffer(ba::const_buffer(&fHeader, sizeof(FTM::Header))));
411// AsyncWait(deadline_, 3, &tcp_connection::check_deadline);
412
413 return;
414 }
415
416 AsyncWait(deadline_, 3, &tcp_connection::check_deadline);
417 }
418
419 void SendDynData(const boost::system::error_code &)
420 {
421 if (!is_open())
422 {
423 // For example: Here we could schedule a new accept if we
424 // would not want to allow two connections at the same time.
425 return;
426 }
427
428 // Check whether the deadline has passed. We compare the deadline
429 // against the current time since a new asynchronous operation
430 // may have moved the deadline before this actor had a chance
431 // to run.
432 if (deadline_.expires_at() <= ba::deadline_timer::traits_type::now())
433 return;
434
435 // The deadline has passed.
436 SendDynamicData();
437
438 AsyncWait(fTriggerDynData, 1, &tcp_connection::SendDynData);
439 return;
440 }
441
442public:
443 typedef boost::shared_ptr<tcp_connection> shared_ptr;
444
445 static shared_ptr create(ba::io_service& io_service)
446 {
447 return shared_ptr(new tcp_connection(io_service));
448 }
449
450 void start()
451 {
452 // Ownership of buffer must be valid until Handler is called.
453
454 // Emit something to be written to the socket
455 fBufCommand.resize(5);
456 AsyncRead(ba::buffer(fBufCommand));
457
458 AsyncWait(fTriggerDynData, 1, &tcp_connection::SendDynData);
459
460// AsyncWrite(ba::buffer(ba::const_buffer(&fHeader, sizeof(FTM::Header))));
461// AsyncWait(deadline_, 3, &tcp_connection::check_deadline);
462
463 }
464};
465
466
467class tcp_server : public tcp::acceptor
468{
469public:
470 tcp_server(ba::io_service& ioservice, int port) :
471 tcp::acceptor(ioservice, tcp::endpoint(tcp::v4(), port))
472
473 {
474 // We could start listening for more than one connection
475 // here, but since there is only one handler executed each time
476 // it would not make sense. Before one handle_accept is not
477 // finished no new handle_accept will be called.
478 // Workround: Start a new thread in handle_accept
479 start_accept();
480 }
481
482private:
483 void start_accept()
484 {
485 cout << "Start accept..." << flush;
486 tcp_connection::shared_ptr new_connection = tcp_connection::create(/*acceptor_.*/io_service());
487
488 // This will accept a connection without blocking
489 async_accept(*new_connection,
490 boost::bind(&tcp_server::handle_accept,
491 this,
492 new_connection,
493 ba::placeholders::error));
494
495 cout << "start-done." << endl;
496 }
497
498 void handle_accept(tcp_connection::shared_ptr new_connection, const boost::system::error_code& error)
499 {
500 // The connection has been accepted and is now ready to use
501
502 // not installing a new handler will stop run()
503 cout << "Handle accept..." << flush;
504 if (!error)
505 {
506 new_connection->start();
507
508 // The is now an open connection/server (tcp_connection)
509 // we immediatly schedule another connection
510 // This allowed two client-connection at the same time
511 start_accept();
512 }
513 cout << "handle-done." << endl;
514 }
515};
516
517int main(int argc, const char **argv)
518{
519 try
520 {
521 ba::io_service io_service;
522
523 Port = argc==2 ? lexical_cast<int>(argv[1]) : 5000;
524
525 tcp_server server(io_service, Port);
526 // ba::add_service(io_service, &server);
527 // server.add_service(...);
528 cout << "Run..." << flush;
529
530 // Calling run() from a single thread ensures no concurrent access
531 // of the handler which are called!!!
532 io_service.run();
533
534 cout << "end." << endl;
535 }
536 catch (std::exception& e)
537 {
538 std::cerr << e.what() << std::endl;
539 }
540
541 return 0;
542}
543/* ====================== Buffers ===========================
544
545char d1[128]; ba::buffer(d1));
546std::vector<char> d2(128); ba::buffer(d2);
547boost::array<char, 128> d3; by::buffer(d3);
548
549// --------------------------------
550char d1[128];
551std::vector<char> d2(128);
552boost::array<char, 128> d3;
553
554boost::array<mutable_buffer, 3> bufs1 = {
555 ba::buffer(d1),
556 ba::buffer(d2),
557 ba::buffer(d3) };
558sock.read(bufs1);
559
560std::vector<const_buffer> bufs2;
561bufs2.push_back(boost::asio::buffer(d1));
562bufs2.push_back(boost::asio::buffer(d2));
563bufs2.push_back(boost::asio::buffer(d3));
564sock.write(bufs2);
565
566
567// ======================= Read functions =========================
568
569ba::async_read_until --> delimiter
570
571streambuf buf; // Ensure validity until handler!
572by::async_read(s, buf, ....);
573
574ba::async_read(s, ba:buffer(data, size), handler);
575 // Single buffer
576 boost::asio::async_read(s,
577 ba::buffer(data, size),
578 compl-func --> ba::transfer_at_least(32),
579 handler);
580
581 // Multiple buffers
582boost::asio::async_read(s, buffers,
583 compl-func --> boost::asio::transfer_all(),
584 handler);
585 */
586
587// ================= Others ===============================
588
589 /*
590 strand Provides serialised handler execution.
591 work Class to inform the io_service when it has work to do.
592
593
594io_service::
595dispatch Request the io_service to invoke the given handler.
596poll Run the io_service's event processing loop to execute ready
597 handlers.
598poll_one Run the io_service's event processing loop to execute one ready
599 handler.
600post Request the io_service to invoke the given handler and return
601 immediately.
602reset Reset the io_service in preparation for a subsequent run()
603 invocation.
604run Run the io_service's event processing loop.
605run_one Run the io_service's event processing loop to execute at most
606 one handler.
607stop Stop the io_service's event processing loop.
608wrap Create a new handler that automatically dispatches the wrapped
609 handler on the io_service.
610
611strand:: The io_service::strand class provides the ability to
612 post and dispatch handlers with the guarantee that none
613 of those handlers will execute concurrently.
614
615dispatch Request the strand to invoke the given handler.
616get_io_service Get the io_service associated with the strand.
617post Request the strand to invoke the given handler and return
618 immediately.
619wrap Create a new handler that automatically dispatches the
620 wrapped handler on the strand.
621
622work:: The work class is used to inform the io_service when
623 work starts and finishes. This ensures that the io_service's run() function will not exit while work is underway, and that it does exit when there is no unfinished work remaining.
624get_io_service Get the io_service associated with the work.
625work Constructor notifies the io_service that work is starting.
626
627*/
628
629
Note: See TracBrowser for help on using the repository browser.