Changeset 14325


Ignore:
Timestamp:
08/07/12 23:12:23 (12 years ago)
Author:
neise
Message:
debugged a typo
File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/FACT++/src/agilentctrl.cc

    r14324 r14325  
    5959    }
    6060   
    61     boost::asio::deadline_timer fCheckStatusTimer;
    62     boost::asio::deadline_timer fAntiFloddingTimer;
    63 
    64     void PostStatusRequest()
    65     {
    66         PostMessage(string("*IDN?\n"));
    67         PostMessage(string("meas:volt?\n"));
    68         PostMessage(string("meas:curr?\n"));
    69     }
    70 
     61boost::asio::deadline_timer fCheckStatusTimer;
     62boost::asio::deadline_timer fAntiFloddingTimer;
     63
     64void PostStatusRequest()
     65{
     66    PostMessage(string("*IDN?\n"));
     67    PostMessage(string("meas:volt?\n"));
     68    PostMessage(string("meas:curr?\n"));
     69}
     70
     71
     72void RequestStatus()
     73{
     74    PostStatusRequest();
     75
     76    fCheckStatusTimer.expires_from_now(boost::posix_time::seconds(60));
     77    fCheckStatusTimer.async_wait(boost::bind(&ConnectionAgilent::HandleRequest,
     78                                      this, bapla::error));
     79}
     80
     81void HandleRequest(const bs::error_code &error)
     82{
     83    // 125: Operation canceled (bs::error_code(125, bs::system_category))
     84    if (error && error!=ba::error::basic_errors::operation_aborted)
     85    {
     86        ostringstream str;
     87        str << "Write timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
     88        Error(str);
     89
     90        PostClose(false);
     91        return;
     92    }
     93
     94    if (!is_open())
     95    {
     96        // For example: Here we could schedule a new accept if we
     97        // would not want to allow two connections at the same time.
     98        PostClose(true);
     99        return;
     100    }
     101
     102    // Check whether the deadline has passed. We compare the deadline
     103    // against the current time since a new asynchronous operation
     104    // may have moved the deadline before this actor had a chance
     105    // to run.
     106    if (fCheckStatusTimer.expires_at() > ba::deadline_timer::traits_type::now())
     107        return;
     108
     109    RequestStatus();
     110}
     111private:
     112
     113int  fLineCounter;
     114
     115void Start_async_read_until()
     116{
     117    // Bind Received Data Handler to the event: "received <enter> character"
     118    //   this Handler will try to parse the incoming data
     119    ba::async_read_until(*this, fBuffer, "\n",
     120                         boost::bind(&ConnectionAgilent::ReceivedStatusHandler, this,
     121                                     bapla::error, bapla::bytes_transferred, 0));
     122
     123    // FIXME: Add timeout here
     124}
     125
     126void ReceivedStatusHandler(const bs::error_code& err, size_t bytes_received, int /*type*/)
     127{
    71128   
    72     void RequestStatus()
    73     {
    74         PostStatusRequest();
    75 
    76         fCheckStatusTimer.expires_from_now(boost::posix_time::seconds(60));
    77         fCheckStatusTimer.async_wait(boost::bind(&ConnectionAgilent::HandleRequest,
    78                                           this, bapla::error));
    79     }
    80 
    81     void HandleRequest(const bs::error_code &error)
    82     {
    83         // 125: Operation canceled (bs::error_code(125, bs::system_category))
    84         if (error && error!=ba::error::basic_errors::operation_aborted)
     129    // Do not schedule a new read if the connection failed.
     130    if (bytes_received==0 || err)
     131    {
     132        if (err==ba::error::eof)
     133            Warn("Connection closed by remote host (FTM).");
     134
     135        // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
     136        // 125: Operation canceled
     137        if (err && err!=ba::error::eof &&                     // Connection closed by remote host
     138            err!=ba::error::basic_errors::not_connected &&    // Connection closed by remote host
     139            err!=ba::error::basic_errors::operation_aborted)  // Connection closed by us
    85140        {
    86141            ostringstream str;
    87             str << "Write timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
     142            str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
    88143            Error(str);
    89 
    90             PostClose(false);
    91             return;
    92144        }
    93 
    94         if (!is_open())
     145        PostClose(err!=ba::error::basic_errors::operation_aborted);
     146        return;
     147    }
     148
     149    if (fIsVerbose)
     150    {
     151       Out() << kBold << "Received (" << bytes_received << " bytes):" << endl;
     152    }
     153    // FIXME: the piece of code below causes a Seg Fault in case
     154    // The Agilent is not listening during program start, then after a while is
     155    // listening and after connection established.
     156    // It sends: 1.) a string and 2.) and empty line (just an <Enter> pressed)
     157    //
     158    // then the agilent_ctrl segfaults ... was able to reproduce it.
     159    // gdp just gave me the hint, that Time().GetAdStr() caused the Seg Fault in a way...
     160    // Is Time threadsafe?
     161    /*
     162    if (fDump)
     163    {
     164        ostringstream msg;
     165        msg << "--- " << Time().GetAsStr() << " --- received " << bytes_received << " bytes.";
     166        Dump(msg.str());
     167    }
     168    */
     169
     170
     171    istream is(&fBuffer);
     172    fLineCounter++;
     173
     174    if (fLineCounter == 1)
     175    {
     176        // this is the Agilent identity string, do nothing
     177        string s;
     178        getline(is,s, '\n');
     179        Out() << "ID string: " << s << endl;
     180    }
     181    else if (fLineCounter == 2)
     182    {
     183        // this should be a float containing the measured voltage
     184        is >> fMeasuredVoltage;
     185        Out() << "voltage: " << fMeasuredVoltage << endl;
     186    }
     187    else if (fLineCounter >= 3)
     188    {
     189        // this should be a float containing the measured voltage
     190        is >> fMeasuredCurrent;
     191        Out() << "current: " << fMeasuredCurrent << endl;
     192        fLineCounter = 0;
     193
     194        // data should contain two floats:
     195        //  * measured output voltage in volts
     196        //  * measured ouput current in amperes
     197        vector<float> data(2);
     198        data[0] = fMeasuredVoltage;
     199        data[1] = fMeasuredCurrent;
     200        UpdateDim(data);
     201    }
     202   
     203    // read the buffer empty ...
     204    // FIXME: I surely misunderstand that damn fBuffer thing.
     205    // I thought it should be emtpy by now...
     206    string buffer;
     207    while (getline(is,buffer, '\n'))
     208    {
     209        buffer = Tools::Trim(buffer);
     210        if (buffer.empty()) continue;
     211    }
     212
     213
     214    if (fMeasuredVoltage > 1.0)
     215    {
     216        fState = State::kVoltage_On;
     217    }
     218    else
     219    {
     220        fState = State::kVoltage_Off;
     221    }
     222    Start_async_read_until();
     223}
     224
     225
     226// This is called when a connection was established
     227void ConnectionEstablished()
     228{
     229    // DN 07.08.2012: The next line is imho not needed.
     230    // But I'm in a train and cannot test it.
     231    fState = State::kConnected;
     232    Start_async_read_until();
     233    RequestStatus();
     234   
     235    fLineCounter = 0;
     236    fBuffer.prepare(1000);
     237}
     238
     239public:
     240
     241ConnectionAgilent(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
     242    fIsVerbose(true),
     243    fDump(true),
     244    fCheckStatusTimer(ioservice),
     245    fAntiFloddingTimer(ioservice)
     246{
     247    SetLogStream(&imp);
     248    fState = State::kDisconnected;
     249    fMeasuredVoltage=-1;
     250    fMeasuredCurrent=-1;
     251}
     252
     253void SetVerbose(bool b)
     254{
     255    fIsVerbose = b;
     256}
     257
     258void SetDumpStream(bool b)
     259{
     260    fDump = b;
     261}
     262
     263void SetOutput(bool b)
     264{
     265    if (b)
     266    {
     267        // check if the previous 'outp off' is some time ago
     268        if (fAntiFloddingTimer.expires_at() < ba::deadline_timer::traits_type::now())
    95269        {
    96             // For example: Here we could schedule a new accept if we
    97             // would not want to allow two connections at the same time.
    98             PostClose(true);
    99             return;
     270            PostMessage(string("outp on\n"));
    100271        }
    101 
    102         // Check whether the deadline has passed. We compare the deadline
    103         // against the current time since a new asynchronous operation
    104         // may have moved the deadline before this actor had a chance
    105         // to run.
    106         if (fCheckStatusTimer.expires_at() > ba::deadline_timer::traits_type::now())
    107             return;
    108 
    109         RequestStatus();
    110     }
     272    }
     273    else
     274    {
     275        PostMessage(string("outp off\n"));
     276        // start a Timer, which runs out in 60sec making sure, that the
     277        // camera can't be switched off&on on short time scales.
     278        // sending repetetive outp off is possible
     279        // sending repetivitve outp on is also posible
     280        // switching off immediately after switching on is also possible.
     281        fAntiFloddingTimer.expires_from_now(boost::posix_time::seconds(60));
     282    }
     283    RequestStatus();
     284}
     285
     286int GetState() const
     287{
     288    // fState is set in ReceivedStatusHandler
     289    return fState;
     290}
     291
     292
     293};
     294
     295// ------------------------------------------------------------------------
     296
     297#include "DimDescriptionService.h"
     298
     299class ConnectionDimAgilent : public ConnectionAgilent
     300{
    111301private:
    112302
    113     int  fLineCounter;
    114 
    115     void Start_async_read_until()
    116     {
    117         // Bind Received Data Handler to the event: "received <enter> character"
    118         //   this Handler will try to parse the incoming data
    119         ba::async_read_until(*this, fBuffer, "\n",
    120                              boost::bind(&ConnectionAgilent::ReceivedStatusHandler, this,
    121                                          bapla::error, bapla::bytes_transferred, 0));
    122 
    123         // FIXME: Add timeout here
    124     }
    125 
    126     void ReceivedStatusHandler(const bs::error_code& err, size_t bytes_received, int /*type*/)
    127     {
    128        
    129         // Do not schedule a new read if the connection failed.
    130         if (bytes_received==0 || err)
    131         {
    132             if (err==ba::error::eof)
    133                 Warn("Connection closed by remote host (FTM).");
    134 
    135             // 107: Transport endpoint is not connected (bs::error_code(107, bs::system_category))
    136             // 125: Operation canceled
    137             if (err && err!=ba::error::eof &&                     // Connection closed by remote host
    138                 err!=ba::error::basic_errors::not_connected &&    // Connection closed by remote host
    139                 err!=ba::error::basic_errors::operation_aborted)  // Connection closed by us
    140             {
    141                 ostringstream str;
    142                 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl;
    143                 Error(str);
    144             }
    145             PostClose(err!=ba::error::basic_errors::operation_aborted);
    146             return;
    147         }
    148 
    149         if (fIsVerbose)
    150         {
    151            Out() << kBold << "Received (" << bytes_received << " bytes):" << endl;
    152         }
    153         // FIXME: the piece of code below causes a Seg Fault in case
    154         // The Agilent is not listening during program start, then after a while is
    155         // listening and after connection established.
    156         // It sends: 1.) a string and 2.) and empty line (just an <Enter> pressed)
    157         //
    158         // then the agilent_ctrl segfaults ... was able to reproduce it.
    159         // gdp just gave me the hint, that Time().GetAdStr() caused the Seg Fault in a way...
    160         // Is Time threadsafe?
    161         /*
    162         if (fDump)
    163         {
    164             ostringstream msg;
    165             msg << "--- " << Time().GetAsStr() << " --- received " << bytes_received << " bytes.";
    166             Dump(msg.str());
    167         }
    168         */
    169 
    170 
    171         istream is(&fBuffer);
    172         fLineCounter++;
    173 
    174         if (fLineCounter == 1)
    175         {
    176             // this is the Agilent identity string, do nothing
    177             string s;
    178             getline(s,buffer, '\n');
    179             Out() << "ID string: " << s << endl;
    180         }
    181         else if (fLineCounter == 2)
    182         {
    183             // this should be a float containing the measured voltage
    184             is >> fMeasuredVoltage;
    185             Out() << "voltage: " << fMeasuredVoltage << endl;
    186         }
    187         else if (fLineCounter >= 3)
    188         {
    189             // this should be a float containing the measured voltage
    190             is >> fMeasuredCurrent;
    191             Out() << "current: " << fMeasuredCurrent << endl;
    192             fLineCounter = 0;
    193 
    194             // data should contain two floats:
    195             //  * measured output voltage in volts
    196             //  * measured ouput current in amperes
    197             vector<float> data(2);
    198             data[0] = fMeasuredVoltage;
    199             data[1] = fMeasuredCurrent;
    200             UpdateDim(data);
    201         }
    202        
    203         // read the buffer empty ...
    204         // FIXME: I surely misunderstand that damn fBuffer thing.
    205         // I thought it should be emtpy by now...
    206         string buffer;
    207         while (getline(is,buffer, '\n'))
    208         {
    209             buffer = Tools::Trim(buffer);
    210             if (buffer.empty()) continue;
    211         }
    212 
    213 
    214         if (fMeasuredVoltage > 1.0)
    215         {
    216             fState = State::kVoltage_On;
    217         }
    218         else
    219         {
    220             fState = State::kVoltage_Off;
    221         }
    222         Start_async_read_until();
    223     }
    224 
    225 
    226     // This is called when a connection was established
    227     void ConnectionEstablished()
    228     {
    229         // DN 07.08.2012: The next line is imho not needed.
    230         // But I'm in a train and cannot test it.
    231         fState = State::kConnected;
    232         Start_async_read_until();
    233         RequestStatus();
    234        
    235         fLineCounter = 0;
    236         fBuffer.prepare(1000);
    237     }
     303DimDescribedService fDim;
     304
     305void Update(DimDescribedService &svc, vector<float> data) const
     306{
     307    svc.Update(data);
     308}
     309
     310void UpdateDim(const vector<float> &data)
     311{
     312    Update(fDim, data);
     313}
     314
    238315
    239316public:
    240 
    241     ConnectionAgilent(ba::io_service& ioservice, MessageImp &imp) : Connection(ioservice, imp()),
    242         fIsVerbose(true),
    243         fDump(true),
    244         fCheckStatusTimer(ioservice),
    245         fAntiFloddingTimer(ioservice)
    246     {
    247         SetLogStream(&imp);
    248         fState = State::kDisconnected;
    249         fMeasuredVoltage=-1;
    250         fMeasuredCurrent=-1;
    251     }
    252 
    253     void SetVerbose(bool b)
    254     {
    255         fIsVerbose = b;
    256     }
    257 
    258     void SetDumpStream(bool b)
    259     {
    260         fDump = b;
    261     }
    262 
    263     void SetOutput(bool b)
    264     {
    265         if (b)
    266         {
    267             // check if the previous 'outp off' is some time ago
    268             if (fAntiFloddingTimer.expires_at() > ba::deadline_timer::traits_type::now())
    269             {
    270                 PostMessage(string("outp on\n"));
    271             }
    272         }
    273         else
    274         {
    275             PostMessage(string("outp off\n"));
    276             // start a Timer, which runs out in 60sec making sure, that the
    277             // camera can't be switched off&on on short time scales.
    278             // sending repetetive outp off is possible
    279             // sending repetivitve outp on is also posible
    280             // switching off immediately after switching on is also possible.
    281             fAntiFloddingTimer.expires_from_now(boost::posix_time::seconds(60));
    282         }
    283         RequestStatus();
    284     }
    285    
    286     int GetState() const
    287     {
    288         // fState is set in ReceivedStatusHandler
    289         return fState;
    290     }
    291 
    292 
    293 };
    294 
    295 // ------------------------------------------------------------------------
    296 
    297 #include "DimDescriptionService.h"
    298 
    299 class ConnectionDimAgilent : public ConnectionAgilent
    300 {
    301 private:
    302 
    303     DimDescribedService fDim;
    304 
    305     void Update(DimDescribedService &svc, vector<float> data) const
    306     {
    307         svc.Update(data);
    308     }
    309 
    310     void UpdateDim(const vector<float> &data)
    311     {
    312         Update(fDim, data);
    313     }
    314 
    315 
    316 public:
    317     ConnectionDimAgilent(ba::io_service& ioservice, MessageImp &imp) :
    318         ConnectionAgilent(ioservice, imp),
    319         fDim("AGILENT_CONTROL/DATA", "F:1;F:1",
    320                     "|U[V]: output voltage"
    321                     "|I[A]: output current")
    322     {
    323         // nothing happens here.
    324     }
     317ConnectionDimAgilent(ba::io_service& ioservice, MessageImp &imp) :
     318    ConnectionAgilent(ioservice, imp),
     319    fDim("AGILENT_CONTROL/DATA", "F:1;F:1",
     320                "|U[V]: output voltage"
     321                "|I[A]: output current")
     322{
     323    // nothing happens here.
     324}
    325325};
    326326
     
    331331{
    332332private:
    333     S fAgilent;
    334 
    335     int Disconnect()
    336     {
    337         // Close all connections
    338         fAgilent.PostClose(false);
    339 
    340         /*
    341          // Now wait until all connection have been closed and
    342          // all pending handlers have been processed
    343          poll();
    344          */
    345 
    346         return T::GetCurrentState();
    347     }
    348 
    349     int Reconnect(const EventImp &evt)
    350     {
    351         // Close all connections to supress the warning in SetEndpoint
    352         fAgilent.PostClose(false);
    353 
    354         // Now wait until all connection have been closed and
    355         // all pending handlers have been processed
    356         poll();
    357 
    358         if (evt.GetBool())
    359             fAgilent.SetEndpoint(evt.GetString());
    360 
    361         // Now we can reopen the connection
    362         fAgilent.PostClose(true);
    363 
    364         return T::GetCurrentState();
    365     }
    366 
    367     int Execute()
    368     {
    369         // Dispatch (execute) at most one handler from the queue. In contrary
    370         // to run_one(), it doesn't wait until a handler is available
    371         // which can be dispatched, so poll_one() might return with 0
    372         // handlers dispatched. The handlers are always dispatched/executed
    373         // synchronously, i.e. within the call to poll_one()
    374         poll_one();
    375        
    376         if ( fAgilent.IsConnected() )
    377             return fAgilent.GetState();
    378         else
     333S fAgilent;
     334
     335int Disconnect()
     336{
     337    // Close all connections
     338    fAgilent.PostClose(false);
     339
     340    /*
     341     // Now wait until all connection have been closed and
     342     // all pending handlers have been processed
     343     poll();
     344     */
     345
     346    return T::GetCurrentState();
     347}
     348
     349int Reconnect(const EventImp &evt)
     350{
     351    // Close all connections to supress the warning in SetEndpoint
     352    fAgilent.PostClose(false);
     353
     354    // Now wait until all connection have been closed and
     355    // all pending handlers have been processed
     356    poll();
     357
     358    if (evt.GetBool())
     359        fAgilent.SetEndpoint(evt.GetString());
     360
     361    // Now we can reopen the connection
     362    fAgilent.PostClose(true);
     363
     364    return T::GetCurrentState();
     365}
     366
     367int Execute()
     368{
     369    // Dispatch (execute) at most one handler from the queue. In contrary
     370    // to run_one(), it doesn't wait until a handler is available
     371    // which can be dispatched, so poll_one() might return with 0
     372    // handlers dispatched. The handlers are always dispatched/executed
     373    // synchronously, i.e. within the call to poll_one()
     374    poll_one();
     375   
     376    if ( fAgilent.IsConnected() )
     377        return fAgilent.GetState();
     378    else
    379379            return State::kDisconnected;
    380380    }
Note: See TracChangeset for help on using the changeset viewer.