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

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