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

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