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

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