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

Last change on this file since 10538 was 10538, checked in by tbretz, 9 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.