Changeset 11927 for trunk/FACT++


Ignore:
Timestamp:
08/31/11 16:54:53 (13 years ago)
Author:
tbretz
Message:
Added the latest changes so that the whole control should become more robust and should disconnect whenever something goes wrong; added ramping and other features.
File:
1 edited

Legend:

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

    r11860 r11927  
    11#include <functional>
     2
     3#include <boost/bind.hpp>
    24
    35#include "Dim.h"
     
    2527class ConnectionBias : public ConnectionUSB
    2628{
    27     vector<uint8_t> fBuffer;
    28 
    29     bool fIsVerbose;
    30 
    3129    enum
    3230    {
     
    3836    enum Command_t
    3937    {
    40         kCmdReset      = 0,
    41         kCmdRead       = 1,
    42         kCmdGlobalSet  = 2,
    43         kCmdChannelSet = 3,
    44         kCmdPrint      = 4
     38        // Communication commands
     39        kCmdReset         =  0,
     40        kCmdRead          =  1,
     41        kCmdGlobalSet     =  2,
     42        kCmdChannelSet    =  3,
     43
     44        // Internal command names
     45        kResetChannels    = 0x10|kCmdChannelSet,
     46        kUpdate           = 0x10|kCmdRead,
     47        kExpertChannelSet = 0x14|kCmdChannelSet,
     48        kSynchronize      = 0x1e,
     49        //kOverCurReset     = 20,
    4550    };
    4651
    47      // Resistance in Ohm for voltage correction
    48 #define RESISTOR float(1000)
     52    enum
     53    {
     54        kMaxDac = 0xfff
     55    };
     56
     57    boost::asio::deadline_timer fSyncTimer;
     58    boost::asio::deadline_timer fRampTimer;
     59    boost::asio::deadline_timer fUpdateTimer;
     60
     61    vector<uint8_t> fBuffer;
     62
     63    bool fIsVerbose;
     64
     65    vector<uint16_t> fVoltCmd;     // Current command voltage in DAC units (12bit = 90V)
     66    vector<uint16_t> fVoltGapd;
     67
     68    vector<bool>     fPresent;
     69
     70    int64_t fWrapCounter;
     71    int64_t fSendCounter;
     72
     73    int16_t fGlobalVoltCmd;      // Command value to be reached
     74//    uint16_t fExpertVoltRef;      // Command value to be reached
     75
     76    int16_t fRampStep;
     77    int16_t fRampTime;
     78
     79    uint16_t fUpdateTime;
     80
     81    bool fIsInitializing;
     82    bool fIsRamping;
     83//    bool fWaitingForAnswer;
    4984
    5085protected:
    51 
    52     vector<uint16_t> fVolt;        // Voltage in DAC units (12bit = 90V)
    53     vector<uint16_t> fRefVolt;
     86    vector<uint16_t> fVolt;        // Current voltage in DAC units (12bit = 90V)
     87    vector<uint16_t> fVoltRef;     // Current reference voltage in DAC units (12bit = 90V)
    5488
    5589    vector<int16_t>  fCurrent;     // Current in ADC units (12bit = 5mA)
    56     vector<int16_t>  fRefCurrent;
    57 
    58     vector<bool>     fPresent;
    59 
    60     int fWrapCounter;
    61 
    6290
    6391    virtual void UpdateA()
     
    7098
    7199private:
    72     void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int type)
    73     {
    74         if (type==kCmdPrint && bytes_received==0 && !err)
    75         {
    76             Print();
    77             return;
    78         }
    79 
     100    bool CheckChDac(const string &cmd, uint16_t dac, uint16_t ch=0)
     101    {
     102        if (dac>kMaxDac)
     103        {
     104            Error(cmd+" - DAC value out of range.");
     105            return false;
     106        }
     107
     108        if (ch>=kNumChannels)
     109        {
     110            Error(cmd+" - Channel out of range.");
     111            return false;
     112        }
     113
     114        return true;
     115    }
     116
     117    vector<char> GetCmd(uint16_t board, uint16_t channel, Command_t cmd, uint16_t dac=0)
     118    {
     119        vector<char> data(3);
     120
     121        /*
     122        if (board>kNumBoards)
     123            return;
     124        if (channel>kNumChannelsPerBoard)
     125            return;
     126        if (dac>0xfff)
     127            return;
     128        */
     129
     130        data[0] = (cmd<<5) | (board<<1) | (((channel&16)>>4) & 1);
     131        data[1] = (channel<<4) | (dac>>8);
     132        data[2] =  dac&0xff;
     133
     134        return data;
     135    }
     136
     137    vector<char> GetCmd(Command_t cmd, uint16_t id=0, uint16_t dac=0)
     138    {
     139        const unsigned int board   = id/kNumChannelsPerBoard;
     140        const unsigned int channel = id%kNumChannelsPerBoard;
     141
     142        return GetCmd(board, channel, cmd, dac);
     143    }
     144
     145    bool CheckMessageLength(int received, int expected, const string &msg)
     146    {
     147        if (received!=expected)
     148            return false;
     149
     150        ostringstream str;
     151        str << msg << ": Expected " << expected << " bytes in answer, but got " << received << endl;
     152        Error(str);
     153
     154        PostClose(false);
     155        return false;
     156    }
     157
     158    bool EvalAnswer(uint8_t *answer, uint16_t id, int command)
     159    {
     160        answer += id*3;
     161
     162        const uint16_t status = (answer[0]>>7)&1;
     163        const uint16_t wrap   = (answer[0]>>4)&7;
     164        const uint16_t ddd    = ((uint16_t(answer[0])&0xf)<<8) | answer[1];
     165        const uint16_t error  = (answer[2]>>4)&0xf;
     166        const uint16_t board  =  answer[2]&0xf;
     167
     168        if (fWrapCounter>=0)
     169        {
     170            if ((fWrapCounter+1)%8 != wrap)
     171            {
     172                ostringstream msg;
     173                msg << "Corrupted answer: received wrap counter " << wrap << " is not last received counter (" << fWrapCounter << "+1)%8.";
     174                Error(msg);
     175                return false;
     176            }
     177        }
     178
     179        fWrapCounter = wrap;
     180
     181        if (command==kSynchronize)
     182        {
     183            ostringstream msg;
     184            msg << hex << setfill('0');
     185            msg << "Initial answer received:";
     186            msg << " 0x" << setw(2) << answer[0];
     187            msg << " 0x" << setw(2) << answer[1];
     188            msg << " 0x" << setw(2) << answer[2];
     189            Message(msg);
     190
     191            if (status!=0 || ddd!=0 || error!=0 || board==0)
     192                Warn("Initial answer doesn't seem to be a reset as naively expected.");
     193
     194            fSendCounter = wrap;
     195
     196            return true;
     197        }
     198
     199        if (error==0x8) // No device
     200        {
     201            Message("Reset button on crate pressed!");
     202            SetZero();
     203            return true;
     204        }
     205
     206        if (command==kCmdReset)
     207        {
     208            if (status==0 && ddd==0 && error==0 && board==0)
     209            {
     210                Message("Reset successfully executed.");
     211                return true;
     212            }
     213
     214            Warn("Answer to 'reset' command contains unexpected data.");
     215            return false;
     216        }
     217
     218        if (command==kCmdGlobalSet)
     219        {
     220            if (status==0 && ddd==0 && error==0 && board==0)
     221            {
     222                for (int i=0; i<kNumChannels; i++)
     223                    fVolt[i] = fGlobalVoltCmd;
     224
     225                fGlobalVoltCmd = -1;
     226
     227                return true;
     228            }
     229
     230            Warn("Answer to 'global set' command contains unexpected data.");
     231            return false;
     232        }
     233
     234        if ((command&0xff)==kExpertChannelSet)
     235            id = command>>8;
     236
     237        const int cmd = command&3;
     238
     239        if (cmd==kCmdRead || cmd==kCmdChannelSet)
     240        {
     241            if (board!=id/kNumChannelsPerBoard)
     242            {
     243                ostringstream out;
     244                out << "Talked to board " << id/kNumChannelsPerBoard << ", but got answer from board " <<  board << ".";
     245                Error(out);
     246                return false;
     247            }
     248
     249            // Not present
     250            if (error==0x7 || error==0xf)
     251            {
     252                fPresent[board] = false;
     253                fCurrent[id]    = 0x8000;
     254                return true;
     255            }
     256
     257            fCurrent[id]    = status ? -ddd : ddd;
     258            fPresent[board] = true;
     259        }
     260
     261        if (cmd==kCmdChannelSet)
     262            fVolt[id] = fVoltCmd[id];
     263
     264        return true;
     265
     266    }
     267
     268private:
     269    void HandleReceivedData(const bs::error_code& err, size_t bytes_received, int command, int send_counter)
     270    {
    80271        // Do not schedule a new read if the connection failed.
    81272        if (bytes_received==0 || err)
     
    94285                Error(str);
    95286            }
    96             PostClose(err!=ba::error::basic_errors::operation_aborted);
    97             return;
    98         }
    99 
     287            PostClose(false);//err!=ba::error::basic_errors::operation_aborted);
     288            return;
     289        }
     290
     291        // Check if the number of received bytes is correctly dividable by 3
     292        // This check should never fail - just for sanity
    100293        if (bytes_received%3)
    101294        {
    102295            Error("Number of received bytes not a multiple of 3, can't read data.");
    103             PostClose(true);
    104             return;
    105         }
    106 
     296            PostClose(false);
     297            return;
     298        }
     299
     300        // Now print the received message if requested by the user
    107301        if (fIsVerbose)
    108302        {
    109             //Out() << endl << kBold << "Data received (size=" << bytes_received << "):" << endl;
    110             //Out() << Converter::GetHex<uint8_t>(fBuffer, 32) << endl;
    111             // FIXME: Check why more is printed than expected
    112         }
    113 
    114         const uint16_t command = type&0xf;
    115         const uint16_t id      = type>>4;
    116         const uint16_t status  = (fBuffer[0]>>7)&1;
    117         const uint16_t wrap    = (fBuffer[0]>>4)&7;
    118         const uint16_t ddd     = ((uint16_t(fBuffer[0])&0xf)<<8) | fBuffer[1];
    119         const uint16_t error   = (fBuffer[2]>>4)&0xf;
    120         const uint16_t board   =  fBuffer[2]&0xf;
    121 
    122         if (fWrapCounter>=0 && (fWrapCounter+1)%8 != wrap)
    123         {
    124             Error("Corrupted answer (wrap counter not as it ought to be.");
    125             return;
    126         }
    127         fWrapCounter = wrap;
    128 
    129         if (error==0x8) // No device
    130         {
    131             ostringstream out;
    132             out << "HV down requested!";
    133             Fatal(out);
    134 
    135             GlobalSetDac(0);
    136 
    137             // Resynchronize input and output
    138             // SystemReset and status request
    139             PostClose(true);
    140 
    141             return;
    142         }
    143 
    144         if (command==kCmdReset)
    145         {
    146             if (status==0 && ddd==0 && error==0 && board==0)
     303            vector<uint32_t> vout((bytes_received/3)*4);
     304
     305            for (size_t i=0; i<bytes_received/3; i++)
    147306            {
    148                 Message("Reset successfully executed.");
     307                vout[i] =
     308                    (uint32_t(fBuffer[i*3+0])<<16) |
     309                    (uint32_t(fBuffer[i*3+1])<< 8) |
     310                    (uint32_t(fBuffer[i*3+2])<< 0);
     311            }
     312
     313            Out() << endl << kBold << "Data received (size=" << bytes_received << "):" << endl;
     314            Out() << " fWrapCounter=" << fWrapCounter << " fSendCounter=" << fSendCounter << " fIsInitializing=" << fIsInitializing << " fIsRamping=" << fIsRamping << endl;
     315            Out() << Converter::GetHex<uint32_t>(vout, 16) << endl;
     316        }
     317
     318        const int cmd = command&0xf;
     319
     320        // Check the number of received_byted according to the answer expected
     321        if ((cmd==kSynchronize      && !CheckMessageLength(bytes_received, 3,                "Synchronization")) ||
     322            (cmd==kCmdReset         && !CheckMessageLength(bytes_received, 3,                "CmdReset"))        ||
     323            (cmd==kCmdRead          && !CheckMessageLength(bytes_received, 3*kNumChannels,   "CmdRead"))         ||
     324            (cmd==kCmdChannelSet    && !CheckMessageLength(bytes_received, 3*kNumChannels,   "CmdChannelSet"))   ||
     325            (cmd==kExpertChannelSet && !CheckMessageLength(bytes_received, 3,                "CmdExpertChannelSet")))
     326            return;
     327
     328        // Now evaluate the whole bunch of messages
     329        for (size_t i=0; i<bytes_received/3; i++)
     330        {
     331            if (!EvalAnswer(fBuffer.data(), i, command))
     332            {
     333                PostClose(false);
    149334                return;
    150335            }
    151 
    152             Warn("Answer to 'reset' command contains unexpected data.");
    153             return;
    154         }
    155 
    156         if (command==kCmdGlobalSet)
    157         {
    158             if (status==0 && ddd==0 && error==0 && board==0)
     336        }
     337
     338        if (send_counter%8 != fWrapCounter)
     339        {
     340            ostringstream msg;
     341            msg << "Corrupted answer: received wrap counter " << fWrapCounter  << " is not send counter " << fSendCounter << "%8.";
     342            Error(msg);
     343            PostClose(false);
     344        }
     345
     346        // Now we are ready to send a new message
     347//        fWaitingForAnswer = false;
     348
     349        if (command==kSynchronize)
     350        {
     351            Message("Stream successfully synchronized.");
     352            fIsInitializing = false;
     353
     354            // Cancel sending of the next 0
     355            fSyncTimer.cancel();
     356
     357            // Start continous reading of all channels
     358            ScheduleUpdate(100);
     359        }
     360
     361        // Take action depending on what is going on
     362        if (command==kCmdReset)
     363            Message("Reset command successfully answered.");
     364
     365        if (cmd==kCmdRead || cmd==kCmdChannelSet || cmd==kExpertChannelSet)
     366        {
     367            UpdateV();
     368            UpdateA();
     369            return;
     370        }
     371
     372        if (cmd==kCmdReset || command==kResetChannels)
     373        {
     374            // Re-start cyclic reading of values after a short time
     375            // to allow the currents to become stable
     376            fUpdateTimer.cancel();
     377            ScheduleUpdate(100);
     378        }
     379
     380        if (command==kUpdate)
     381            ScheduleUpdate(fUpdateTime);
     382
     383        // If we are ramping, schedule a new ramp step
     384        if (command==kCmdChannelSet && fIsRamping)
     385        {
     386            ScheduleRampStep();
     387            return;
     388        }
     389    }
     390
     391    // --------------------------------------------------------------------
     392
     393    void HandleSyncTimer(int counter, const bs::error_code &error)
     394    {
     395        if (error==ba::error::basic_errors::operation_aborted)
     396        {
     397            Warn("Synchronization aborted...");
     398            fIsRamping = false;
     399            return;
     400        }
     401
     402        if (error)
     403        {
     404            ostringstream str;
     405            str << "Synchronization timer: " << error.message() << " (" << error << ")";// << endl;
     406            Error(str);
     407
     408            PostClose(false);
     409            return;
     410        }
     411
     412        if (!is_open())
     413        {
     414            Warn("Synchronization in progress, but disconnected.");
     415            return;
     416        }
     417
     418        ostringstream msg;
     419        msg << "Synchronization time expired (" << counter << ")" << endl;
     420        Info(msg);
     421
     422        if (fIsInitializing)
     423        {
     424            PostMessage("\0", 1);
     425
     426            if (counter==2)
    159427            {
    160                 Message("GlobalSet successfully executed.");
     428                Error("Synchronization attempt timed out.");
     429                PostClose(false);
    161430                return;
    162431            }
    163432
    164             Warn("Answer to 'global set' command contains unexpected data.");
    165             return;
    166         }
    167 
    168         if (command==kCmdRead || command==kCmdChannelSet)
    169         {
    170             if (error==0x7 || error==0xf)
    171             {
    172                 fPresent[board] = false;
    173                 fCurrent[id]    = 0x8000;
    174                 return;
    175             }
    176 
    177             if (board!=id/kNumChannelsPerBoard)
    178             {
    179                 ostringstream out;
    180                 out << "Talked to board " << id/kNumChannelsPerBoard << " but board " <<  board << " answered.";
    181                 Error(out);
    182                 return;
    183             }
    184 
    185             fCurrent[id]    = status ? -ddd : ddd;
    186             fPresent[board] = true;
    187 
    188             UpdateA();
    189 
    190             return;
    191         }
     433            ScheduleSync(counter+1);
     434            return;
     435        }
     436
     437        Info("Synchronisation successfull.");
     438    }
     439
     440    void ScheduleSync(int counter=0)
     441    {
     442        fSyncTimer.expires_from_now(boost::posix_time::milliseconds(333));
     443        fSyncTimer.async_wait(boost::bind(&ConnectionBias::HandleSyncTimer, this, counter, dummy::error));
    192444    }
    193445
     
    195447    void ConnectionEstablished()
    196448    {
    197         fWrapCounter = -1;
    198         fBuffer.resize(3);
    199 
    200         SystemReset();
    201         ReadAllChannels();
    202     }
    203 
    204     void HandleReadTimeout(const bs::error_code &error)
     449        // Reset everything....
     450        fSendCounter    = -1;
     451        fWrapCounter    = -1;
     452        fGlobalVoltCmd  = -1;
     453        fIsInitializing = true;
     454
     455        fVolt.assign(   0, kNumChannels);
     456        fVoltRef.assign(0, kNumChannels);
     457        fVoltCmd.assign(0, kNumChannels);
     458
     459        // Send a single 0 (and possible two consecutive 0's
     460        // to make sure we are in sync with the device)
     461        PostMessage("\0", 1);
     462        AsyncRead(ba::buffer(fBuffer, 3), kSynchronize, ++fSendCounter);
     463//        fWaitingForAnswer = true;
     464
     465        // Wait for some time before sending the next 0
     466        ScheduleSync();
     467    }
     468
     469    // --------------------------------------------------------------------
     470
     471    void HandleUpdateTimer(const bs::error_code &error)
    205472    {
    206473        if (error==ba::error::basic_errors::operation_aborted)
    207             return;
     474        {
     475            Warn("Update timer aborted...");
     476            fIsRamping = false;
     477            return;
     478        }
    208479
    209480        if (error)
    210481        {
    211482            ostringstream str;
    212             str << "Read timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;
     483            str << "Update timer: " << error.message() << " (" << error << ")";// << endl;
    213484            Error(str);
    214485
    215             PostClose();
     486            PostClose(false);
     487            return;
     488        }
     489
     490        if (is_open())
     491            ReadAllChannels(true);
     492    }
     493
     494    void ScheduleUpdate(int millisec)
     495    {
     496        fUpdateTimer.expires_from_now(boost::posix_time::milliseconds(millisec));
     497        fUpdateTimer.async_wait(boost::bind(&ConnectionBias::HandleUpdateTimer, this, dummy::error));
     498    }
     499
     500    // --------------------------------------------------------------------
     501
     502    void SetAllChannels(const vector<uint16_t> &dac, bool special=false)
     503    {
     504        vector<char> data;
     505        data.reserve(kNumChannels*3);
     506
     507        for (int ch=0; ch<kNumChannels; ch++)
     508        {
     509            const vector<char> cmd = GetCmd(kCmdChannelSet, ch, dac[ch]);
     510            data.insert(data.end(), cmd.begin(), cmd.end());
     511
     512            fVoltCmd[ch] = dac[ch];
     513        }
     514
     515        fSendCounter += kNumChannels;
     516
     517        PostMessage(data);
     518        AsyncRead(ba::buffer(fBuffer, kNumChannels*3),
     519                  special ? kResetChannels : kCmdChannelSet, fSendCounter);
     520//        fWaitingForAnswer = true;
     521    }
     522
     523    uint16_t RampOneStep(uint16_t ch)
     524    {
     525        if (fVoltRef[ch]>fVolt[ch])
     526            return fVolt[ch]+fRampStep>fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]+fRampStep;
     527
     528        if (fVoltRef[ch]<fVolt[ch])
     529            return fVolt[ch]-fRampStep<fVoltRef[ch] ? fVoltRef[ch] : fVolt[ch]-fRampStep;
     530
     531        return fVolt[ch];
     532    }
     533
     534    bool RampOneStep()
     535    {
     536        vector<uint16_t> dac(kNumChannels);
     537
     538        bool identical = true;
     539        for (int ch=0; ch<kNumChannels; ch++)
     540        {
     541            dac[ch] = RampOneStep(ch);
     542            if (dac[ch]!=fVolt[ch])
     543                identical = false;
     544        }
     545
     546        SetAllChannels(dac);
     547
     548        if (identical)
     549            Info("Ramping: target values reached.");
     550
     551        return !identical;
     552    }
     553
     554    void HandleRampTimer(const bs::error_code &error)
     555    {
     556        if (error==ba::error::basic_errors::operation_aborted)
     557        {
     558            Warn("Ramping aborted...");
     559            fIsRamping = false;
     560            return;
     561        }
     562
     563        if (error)
     564        {
     565            ostringstream str;
     566            str << "Ramping timer: " << error.message() << " (" << error << ")";// << endl;
     567            Error(str);
     568
     569            PostClose(false);
    216570            return;
    217571        }
     
    219573        if (!is_open())
    220574        {
    221             // For example: Here we could schedule a new accept if we
    222             // would not want to allow two connections at the same time.
    223             return;
    224         }
    225 
    226         // Check whether the deadline has passed. We compare the deadline
    227         // against the current time since a new asynchronous operation
    228         // may have moved the deadline before this actor had a chance
    229         // to run.
    230         if (fInTimeout.expires_at() > ba::deadline_timer::traits_type::now())
    231             return;
    232 
    233         Error("Timeout reading data from "+URL());
    234 
    235         PostClose();
    236     }
    237 
    238     vector<char> GetCmd(uint16_t id, Command_t cmd, uint16_t dac=0)
    239     {
    240         const unsigned int board   = id/kNumChannelsPerBoard;
    241         const unsigned int channel = id%kNumChannelsPerBoard;
    242 
    243         return GetCmd(board, channel, cmd, dac);
    244     }
    245 
    246     vector<char> GetCmd(uint16_t board, uint16_t channel, Command_t cmd, uint16_t dac=0)
    247     {
    248         vector<char> data(3);
    249 
    250         /*
    251         if (board>kNumBoards)
    252             return;
    253         if (channel>kNumChannelsPerBoard)
    254             return;
    255         if (dac>0xfff)
    256             return;
    257         */
    258 
    259         data[0] = (cmd<<5) | (board<<1) | (((channel&16)>>4) & 1);
    260         data[1] = (channel<<4) | (dac>>8);
    261         data[2] =  dac&0xff;
    262 
    263         return data;
    264     }
    265 
    266     /*
    267     void SetChannels(const map<uint16_t, uint16_t> &vals)
    268     {
    269         if (vals.empty())
    270             return;
    271 
    272         // Build and execute commands
    273         for (map<uint16_t, uint16_t>::const_iterator it=vals.begin();
    274              it!=vals.end(); it++)
    275         {
    276             // If DAC value unchanged, do not send command
    277             if (fVolt[it->first] == it->second)
    278                 continue;
    279 
    280             const vector<char> cmd = GetCmd(it->first, kCmdChannelSet, it->second);
    281             PostMessage(cmd);
    282             AsyncRead(ba::buffer(fBuffer), kCmdChannelSet|(it->first<<4));
    283         }
    284     }*/
    285 
    286     /*
    287     // ***** Synchronize board *****
    288     bool Crate::Synch()
    289     {
    290         //############################################################
    291         int Trial = 0;
    292         vector<unsigned char> Data;
    293 
    294         while(++Trial <= 3) {
    295             Data = Communicate(string(1, 0));
    296             if (Data.size() == 3) return true;
    297         }
    298         return false;
    299         //############################################################
    300     }
    301     */
     575            Warn("Ramping in progress, but disconnected.");
     576            return;
     577        }
     578
     579        if (!fIsRamping)
     580        {
     581            Error("Ramp handler called although no ramping in progress.");
     582            return;
     583        }
     584
     585        fIsRamping = RampOneStep();
     586    }
     587
     588    void ScheduleRampStep()
     589    {
     590        fRampTimer.expires_from_now(boost::posix_time::milliseconds(fRampTime));
     591        fRampTimer.async_wait(boost::bind(&ConnectionBias::HandleRampTimer, this, dummy::error));
     592    }
    302593
    303594public:
    304595    ConnectionBias(ba::io_service& ioservice, MessageImp &imp) : ConnectionUSB(ioservice, imp()),
     596        fSyncTimer(ioservice),
     597        fRampTimer(ioservice),
     598        fUpdateTimer(ioservice),
     599        fBuffer(3*kNumChannels),
    305600        fIsVerbose(true),
     601        fVoltCmd(kNumChannels),
     602        fVoltGapd(kNumChannels),
     603        //fRefCurrent(kNumChannels),
     604        fPresent(kNumBoards),
     605        fRampStep(-1),
     606        fRampTime(-1),
     607        fUpdateTime(3000),
     608        fIsRamping(false),
    306609        fVolt(kNumChannels),
    307         fRefVolt(kNumChannels),
    308         fCurrent(kNumChannels),
    309         fRefCurrent(kNumChannels),
    310         fPresent(kNumBoards)
     610        fVoltRef(kNumChannels),
     611        fCurrent(kNumChannels)
    311612    {
    312613        SetLogStream(&imp);
    313614    }
    314615
    315     void SystemReset()
    316     {
    317         Message("Sending system reset.");
    318         PostMessage(GetCmd(0, kCmdReset));
    319         AsyncRead(ba::buffer(fBuffer), kCmdReset);
    320     }
    321 
    322     void ReadChannel(int ch)
    323     {
    324         PostMessage(GetCmd(ch, kCmdRead));
    325         AsyncRead(ba::buffer(fBuffer), kCmdRead|(ch<<4));
    326     }
    327 
    328 
    329     void ReadAllChannels()
    330     {
    331         Message("Requesting full system status.");
    332 
    333         // Prepare command to read all channels
    334         for (int i=0; i<kNumChannels; i++)
    335             ReadChannel(i);
    336 
    337         //vector<char> buf;
    338         //AsyncRead(ba::buffer(buf), kCmdPrint);
     616    void OverCurrentReset()
     617    {
     618        if (fIsRamping)
     619        {
     620            Warn("OverCurrentReset - Ramping in progres.");
     621            RampStop();
     622        }
     623
     624        vector<uint16_t> dac(kNumChannels);
     625
     626        for (int ch=0; ch<kNumChannels; ch++)
     627            dac[ch] = fCurrent[ch]<0 ? 0 : fVolt[ch];
     628
     629        SetAllChannels(dac, true);
     630    }
     631
     632    void ReadAllChannels(bool special = false)
     633    {
     634        vector<char> data;
     635        data.reserve(kNumChannels*3);
     636
     637        for (int ch=0; ch<kNumChannels; ch++)
     638        {
     639            const vector<char> cmd = GetCmd(kCmdRead, ch);
     640            data.insert(data.end(), cmd.begin(), cmd.end());
     641        }
     642
     643        fSendCounter += kNumChannels;
     644
     645        PostMessage(data);
     646        AsyncRead(ba::buffer(fBuffer, kNumChannels*3),
     647                  special ? kUpdate : kCmdRead, fSendCounter);
     648//        fWaitingForAnswer = true;
     649    }
     650
     651    // --------------------------------------------------------------------
     652
     653    bool ChannelSetDac(uint16_t ch, uint16_t dac)
     654    {
     655        if (!CheckChDac("ChannelSetDac", dac, ch))
     656            return false;
     657
     658        fVoltRef[ch] = dac;
     659
     660        if (!fIsRamping)
     661            fIsRamping = RampOneStep();
     662
     663        return true;
     664    }
     665
     666    bool ChannelSetVolt(uint16_t ch, double volt)
     667    {
     668        return ChannelSetDac(ch, volt*4096/90.);
    339669    }
    340670
    341671    bool GlobalSetDac(uint16_t dac)
    342672    {
    343         if (dac>0xfff)
    344             return false;
    345 
    346         PostMessage(GetCmd(0, kCmdGlobalSet, dac));
    347         AsyncRead(ba::buffer(fBuffer), kCmdGlobalSet);
    348 
    349         ReadAllChannels();
    350 
    351         fVolt.assign(kNumChannels, dac);
    352         UpdateV();
     673        if (!CheckChDac("GlobalSetDac", dac))
     674            return false;
     675
     676        for (size_t ch=0; ch<kNumChannels; ch++)
     677            fVoltRef[ch] = dac;
     678
     679        if (!fIsRamping)
     680            fIsRamping = RampOneStep();
    353681
    354682        return true;
    355683    }
    356684
    357     bool GlobalSet(double voltage)
    358     {
    359         return GlobalSetDac(voltage*4096/90);
    360     }
    361 
    362     bool ChannelSetDac(uint16_t ch, uint16_t dac)
    363     {
    364         if (dac>0xfff)
    365             return false;
    366 
    367         if (ch>=kNumChannels)
    368             return false;
    369 
    370         if (fVolt[ch]==dac)
    371             return true;
    372 
    373         PostMessage(GetCmd(ch, kCmdChannelSet, dac));
    374         AsyncRead(ba::buffer(fBuffer), kCmdChannelSet|(ch<<4));
    375 
    376         ReadChannel(ch);
    377 
    378         fVolt[ch] = dac;
    379         UpdateV();
     685    bool GlobalSetVolt(float volt)
     686    {
     687        return GlobalSetDac(volt*4096/90);
     688    }
     689
     690    // --------------------------------------------------------------------
     691
     692    bool SetGapdVoltage()
     693    {
     694        for (size_t ch=0; ch<kNumChannels; ch++)
     695            if (fVoltGapd[ch]>kMaxDac)
     696            {
     697                Error("SetGapdVoltage - Voltage reference for G-APD channel out of range.");
     698                return false;
     699            }
     700
     701        for (size_t ch=0; ch<kNumChannels; ch++)
     702            fVoltRef[ch] = fVoltGapd[ch];
     703
     704        if (!fIsRamping)
     705            fIsRamping = RampOneStep();
    380706
    381707        return true;
    382708    }
    383709
    384     bool ChannelSet(uint16_t ch, double voltage)
    385     {
    386         return ChannelSetDac(ch, voltage*4096/90);
    387     }
    388 
    389     void SetVoltage(int ch, int32_t dac)
    390     {
    391         if (dac<0)
    392             dac = 0;
    393 
    394         if (dac>0xfff)
    395             dac = 0xfff;
    396 
    397         ChannelSetDac(ch, dac);
    398     }
    399 
    400     // ***** Correct voltages according to current *****
    401     void AdaptVoltages()
    402     {
    403         for (int i=0; i<kNumChannels; i++)
    404         {
    405             if (fRefVolt[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
    406                 continue;
    407 
    408             // Calculate difference and convert ADC units to Amp
    409             // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
    410             //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
    411 
    412             // Calculate voltage difference
    413             // #define RESISTOR 1000 // Ohm
    414             //const double diffvolt = diffcur*RESISTOR/1e6;
    415 
    416             // Calculate new vlaue by onverting voltage difference to DAC units
    417             //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
    418             SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
    419         }
    420     }
    421 
    422     void SetReferenceCurrent()
    423     {
    424         fRefCurrent = fCurrent;
    425     }
    426 
    427     bool SetReferenceVoltage(const vector<float> &volt)
     710    void SetZero()
     711    {
     712        for (size_t ch=0; ch<kNumChannels; ch++)
     713            fVoltRef[ch] = 0;
     714
     715        if (!fIsRamping)
     716            fIsRamping = RampOneStep();
     717    }
     718
     719    bool SetNewGapdVoltage(const vector<float> &volt)
    428720    {
    429721        if (volt.size()!=kNumChannels)
    430722        {
    431723            ostringstream out;
    432             out << "SetReferenceVoltage - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
     724            out << "SetNewGapdVoltage - Given vector has " << volt.size() << " elements - expected " << kNumChannels << endl;
    433725            Error(out);
    434726            return false;
    435727        }
    436728
    437         for (size_t i=0; i<volt.size(); i++)
    438             fRefVolt[i] = volt[i]*4096/90;
     729        for (size_t i=0; i<kNumChannels; i++)
     730            fVoltGapd[i] = volt[i]*4096/90;
    439731
    440732        return true;
    441733    }
    442734
    443     void ApplyReferenceVoltage()
    444     {
    445         for (size_t i=0; i<fRefVolt.size(); i++)
    446             SetVoltage(i, fRefVolt[i]);
    447     }
     735    // --------------------------------------------------------------------
     736
     737    void RampStop()
     738    {
     739        fRampTimer.cancel();
     740        fIsRamping = false;
     741
     742        Message("Ramping stopped.");
     743    }
     744
     745    void RampStart()
     746    {
     747        if (fIsRamping)
     748        {
     749            Warn("RampStart - Ramping in progress... ignored.");
     750            return;
     751        }
     752
     753        fIsRamping = RampOneStep();
     754    }
     755
     756    void SetRampTime(uint16_t val)
     757    {
     758        fRampTime = val;
     759    }
     760
     761    void SetRampStep(uint16_t val)
     762    {
     763        fRampStep = val;
     764    }
     765
     766    bool IsRamping() const { return fIsRamping; }
     767
     768    // -------------------------------------------------------------------
     769
     770    void ExpertReset()
     771    {
     772        Warn("EXPERT MODE: Sending reset.");
     773        PostMessage(GetCmd(kCmdReset));
     774        AsyncRead(ba::buffer(fBuffer, 3), kCmdReset);
     775//        fWaitingForAnswer = true;
     776    }
     777
     778
     779    bool ExpertChannelSetDac(uint16_t ch, uint16_t dac)
     780    {
     781        if (!CheckChDac("ExpertChannelSetDac", dac, ch))
     782            return false;
     783
     784        fVoltCmd[ch] = dac;
     785
     786        // FIXME: How to ensure the correct evaluation of the answer?
     787
     788        ostringstream msg;
     789        msg << "EXPERT MODE: Sending 'ChannelSet' (set ch " << ch << " to DAC=" << dac << ")";
     790        Warn(msg);
     791
     792        PostMessage(GetCmd(kCmdChannelSet, ch, dac));
     793        AsyncRead(ba::buffer(fBuffer, 3), kExpertChannelSet|(ch<<8), ++fSendCounter);
     794//        fWaitingForAnswer = true;
     795
     796        return true;
     797    }
     798
     799    bool ExpertChannelSetVolt(uint16_t ch, double volt)
     800    {
     801        return ExpertChannelSetDac(ch, volt*4096/90.);
     802    }
     803
     804    bool ExpertGlobalSetDac(uint16_t dac)
     805    {
     806        if (!CheckChDac("ExpertGlobalSetDac", dac))
     807            return false;
     808
     809        if (fGlobalVoltCmd>=0)
     810        {
     811            Error("ExpertGlobalSetDac - Still waiting for previous global-set's answer.");
     812            return false;
     813        }
     814
     815        fGlobalVoltCmd = dac;
     816
     817        ostringstream msg;
     818        msg << "EXPERT MODE: Sending 'GlobalSet' (DAC=" << dac << ")";
     819        Warn(msg);
     820
     821        PostMessage(GetCmd(kCmdGlobalSet, 0, dac));
     822        AsyncRead(ba::buffer(fBuffer, 3), kCmdGlobalSet, ++fSendCounter);
     823//        fWaitingForAnswer = true;
     824
     825        return true;
     826    }
     827
     828    bool ExpertGlobalSetVolt(float volt)
     829    {
     830        return GlobalSetDac(volt*4096/90);
     831    }
     832
     833    // --------------------------------------------------------------------
    448834
    449835    void SetVerbose(bool b)
     
    468854
    469855    }
     856
    470857    void Print()
    471858    {
     
    485872        }
    486873    }
     874
     875    // -------------------------------------------------------------------
     876/*
     877    void AdaptVoltages()
     878    {
     879        // Correct voltages according to current
     880        for (int i=0; i<kNumChannels; i++)
     881        {
     882            if (fVoltRef[i]==0 || fCurrent[i]<0 || fRefCurrent[i]<0)
     883                continue;
     884
     885            // Calculate difference and convert ADC units to Amp
     886            // const double diffcur = (fRefCurrent[i]-fCurrent[i])*5000/4096
     887            //const int32_t diffcur = int32_t(fRefCurrent[i]-fCurrent[i])*5000;
     888
     889            // Calculate voltage difference
     890            // #define RESISTOR 1000 // Ohm
     891            //const double diffvolt = diffcur*RESISTOR/1e6;
     892
     893            // Calculate new vlaue by onverting voltage difference to DAC units
     894            //const int32_t dac = fRefVolt[i] + diffvolt*4096/90.0;
     895            SetVoltage(i, fRefVolt[i] + (fRefCurrent[i]-fCurrent[i])/18);
     896        }
     897    }
     898
     899    void SetReferenceCurrent()
     900    {
     901        fRefCurrent = fCurrent;
     902    }
     903    */
     904
     905    enum States_t
     906    {
     907        kDisconnected = StateMachineImp::kSM_UserMode,
     908        kConnecting,
     909        kInitializing,
     910        kConnected,
     911        kRamping,
     912        kExpertMode // 'forward' declaration to be used in StateMachineBias
     913    };
     914
     915    int GetStatus()
     916    {
     917        if (!IsConnected())
     918            return kDisconnected;
     919
     920        if (IsConnecting())
     921            return kConnecting;
     922
     923        if (fIsInitializing)
     924            return kInitializing;
     925
     926        if (fIsRamping)
     927            return kRamping;
     928
     929        return kConnected;
     930    }
    487931};
    488932
     
    505949    void UpdateV()
    506950    {
    507         fDimVoltage.Update(fVolt);
    508     }
     951        vector<uint16_t> vec;
     952        vec.insert(vec.end(), fVolt.begin(),    fVolt.end());
     953        vec.insert(vec.end(), fVoltRef.begin(), fVoltRef.end());
     954        fDimVoltage.Update(vec);
     955    }
     956
    509957
    510958public:
     
    512960        ConnectionBias(ioservice, imp),
    513961        fDimCurrent("BIAS_CONTROL/CURRENT", "S:416", ""),
    514         fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416", "")
     962        fDimVoltage("BIAS_CONTROL/VOLTAGE", "S:416;S:416", "")
    515963    {
    516964    }
     
    549997    S fBias;
    550998
    551     enum states_t
    552     {
    553         kStateDisconnected = 1,
    554         kStateConnected    = 2,
    555     };
    556 
    557     int SetGlobal(const EventImp &evt)
    558     {
    559         if (!CheckEventSize(evt.GetSize(), "SetGlobal", 4))
    560             return false;
    561 
    562         if (!fBias.GlobalSet(evt.GetFloat()))
     999    bool fExpertMode;
     1000
     1001    // --------------------------------------------------------------------
     1002
     1003    int SetGlobalVolt(const EventImp &evt)
     1004    {
     1005        if (!CheckEventSize(evt.GetSize(), "SetGlobalVolt", 4))
     1006            return false;
     1007
     1008        if (!fBias.GlobalSetVolt(evt.GetFloat()))
    5631009            T::Error("Supplied voltage out of range (0-90)");
    5641010
     
    5771023    }
    5781024
    579     int SetChannel(const EventImp &evt)
    580     {
    581         if (!CheckEventSize(evt.GetSize(), "SetChannel", 6))
    582             return false;
    583 
    584         if (!fBias.ChannelSet(evt.GetUShort(), evt.Get<float>(2)))
     1025    int SetChannelVolt(const EventImp &evt)
     1026    {
     1027        if (!CheckEventSize(evt.GetSize(), "SetChannelVolt", 6))
     1028            return false;
     1029
     1030        if (!fBias.ChannelSetVolt(evt.GetUShort(), evt.Get<float>(2)))
    5851031            T::Error("Value out of range");
    5861032
     
    5991045    }
    6001046
     1047    // --------------------------------------------------------------------
     1048
     1049    int ExpertSetGlobalVolt(const EventImp &evt)
     1050    {
     1051        if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalVolt", 4))
     1052            return false;
     1053
     1054        if (!fBias.ExpertGlobalSetVolt(evt.GetFloat()))
     1055            T::Error("Supplied voltage out of range (0-90)");
     1056
     1057        return T::GetCurrentState();
     1058    }
     1059
     1060    int ExpertSetGlobalDac(const EventImp &evt)
     1061    {
     1062        if (!CheckEventSize(evt.GetSize(), "ExpertSetGlobalDac", 2))
     1063            return false;
     1064
     1065        if (!fBias.ExpertGlobalSetDac(evt.GetUShort()))
     1066            T::Error("Supplied voltage out of range (0-90)");
     1067
     1068        return T::GetCurrentState();
     1069    }
     1070
     1071    int ExpertSetChannelVolt(const EventImp &evt)
     1072    {
     1073        if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelVolt", 6))
     1074            return false;
     1075
     1076        if (!fBias.ExpertChannelSetVolt(evt.GetUShort(), evt.Get<float>(2)))
     1077            T::Error("Value out of range");
     1078
     1079        return T::GetCurrentState();
     1080    }
     1081
     1082    int ExpertSetChannelDac(const EventImp &evt)
     1083    {
     1084        if (!CheckEventSize(evt.GetSize(), "ExpertSetChannelDac", 4))
     1085            return false;
     1086
     1087        if (!fBias.ExpertChannelSetDac(evt.Get<uint16_t>(), evt.Get<uint16_t>(2)))
     1088            T::Error("Value out of range");
     1089
     1090        return T::GetCurrentState();
     1091    }
     1092
     1093    // --------------------------------------------------------------------
    6011094
    6021095    int Disconnect()
     
    6281121        // Now we can reopen the connection
    6291122        fBias.PostClose(true);
     1123
     1124        return T::GetCurrentState();
     1125    }
     1126
     1127    int SetVerbosity(const EventImp &evt)
     1128    {
     1129        if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
     1130            return T::kSM_FatalError;
     1131
     1132        fBias.SetVerbose(evt.GetBool());
     1133
     1134        return T::GetCurrentState();
     1135    }
     1136
     1137    int SetExpertMode(const EventImp &evt)
     1138    {
     1139        if (!CheckEventSize(evt.GetSize(), "SetExpertMode", 1))
     1140            return T::kSM_FatalError;
     1141
     1142        fExpertMode = evt.GetBool();
     1143
     1144        if (fExpertMode)
     1145            T::Warn("Expert commands enabled -- please ensure that you EXACTLY know what you do. These commands can destroy the system.");
    6301146
    6311147        return T::GetCurrentState();
     
    6411157        poll_one();
    6421158
    643         return fBias.IsConnected() ? kStateConnected : kStateDisconnected;
    644     }
    645 
    646     int SetVerbosity(const EventImp &evt)
    647     {
    648         if (!CheckEventSize(evt.GetSize(), "SetVerbosity", 1))
    649             return T::kSM_FatalError;
    650 
    651         fBias.SetVerbose(evt.GetBool());
    652 
    653         return T::GetCurrentState();
     1159        return fExpertMode && fBias.GetStatus()==ConnectionBias::kConnected ?
     1160            ConnectionBias::kExpertMode : fBias.GetStatus();
    6541161    }
    6551162
     
    6571164    StateMachineBias(ostream &out=cout) :
    6581165        T(out, "BIAS_CONTROL"), ba::io_service::work(static_cast<ba::io_service&>(*this)),
    659         fBias(*this, *this)
     1166        fBias(*this, *this), fExpertMode(false)
    6601167    {
    6611168        // ba::io_service::work is a kind of keep_alive for the loop.
     
    6661173        // deletion and creation of threads and more.
    6671174
     1175        T::Warn("FIXME -- implement a state for 'at reference'");
     1176
    6681177        // State names
    669         AddStateName(kStateDisconnected, "Disconnected",
    670                      "Bias-power supply not connected via USB.");
    671 
    672         AddStateName(kStateConnected, "Connected",
    673                      "USB connection to bias-power supply established.");
     1178        T::AddStateName(ConnectionBias::kDisconnected, "Disconnected",
     1179                        "Bias-power supply not connected via USB.");
     1180
     1181        T::AddStateName(ConnectionBias::kConnecting, "Connecting",
     1182                        "Trying to establish USB connection to bias-power supply.");
     1183
     1184        T::AddStateName(ConnectionBias::kInitializing, "Initializing",
     1185                        "USB connection to bias-power supply established, synchronizing USB stream.");
     1186
     1187        T::AddStateName(ConnectionBias::kConnected, "Connected",
     1188                        "USB connection to bias-power supply established.");
     1189
     1190        T::AddStateName(ConnectionBias::kExpertMode, "ExpertMode",
     1191                        "Special (risky!) mode to directly send command to the bias-power supply.");
     1192
     1193        T::AddStateName(ConnectionBias::kRamping, "Ramping",
     1194                        "Voltage ramping in progress.");
    6741195
    6751196        // Verbosity commands
    6761197        T::AddEvent("SET_VERBOSE", "B")
    677             (bind(&StateMachineBias::SetVerbosity, this, _1))
     1198            (bind(&StateMachineBias::SetVerbosity, this, placeholders::_1))
    6781199            ("set verbosity state"
    6791200             "|verbosity[bool]:disable or enable verbosity for received data (yes/no), except dynamic data");
    6801201
    6811202        // Conenction commands
    682         AddEvent("DISCONNECT", kStateConnected)
     1203        T::AddEvent("DISCONNECT", ConnectionBias::kConnected)
    6831204            (bind(&StateMachineBias::Disconnect, this))
    6841205            ("disconnect from ethernet");
    6851206
    686         AddEvent("RECONNECT", "O", kStateDisconnected, kStateConnected)
    687             (bind(&StateMachineBias::Reconnect, this, _1))
     1207        T::AddEvent("RECONNECT", "O", ConnectionBias::kDisconnected, ConnectionBias::kConnected)
     1208            (bind(&StateMachineBias::Reconnect, this, placeholders::_1))
    6881209            ("(Re)connect ethernet connection to FTM, a new address can be given"
    6891210             "|[host][string]:new ethernet address in the form <host:port>");
    6901211
    6911212
    692         AddEvent("REQUEST_STATUS", kStateConnected)
    693             (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias)))
    694             ("");
    695 
    696         AddEvent("SET_GLOBAL_VOLTAGE", "F:1", kStateConnected)
    697             (bind(&StateMachineBias::SetGlobal, this, _1))
    698             ("");
    699 
    700         AddEvent("SET_GLOBAL_DAC", "S:1", kStateConnected)
    701             (bind(&StateMachineBias::SetGlobalDac, this, _1))
    702             ("");
    703 
    704         AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", kStateConnected)
    705             (bind(&StateMachineBias::SetChannel, this, _1))
    706             ("");
    707 
    708         AddEvent("SET_CHANNEL_DAC", "S:1;S:1", kStateConnected)
    709             (bind(&StateMachineBias::SetChannelDac, this, _1))
    710             ("");
    711 
    712         AddEvent("RESET", kStateConnected)
    713             (Wrapper(bind(&ConnectionBias::SystemReset, &fBias)))
    714             ("");
    715 
    716         AddEvent("SET_REFERENCE_CURRENT", kStateConnected)
    717             (Wrapper(bind(&ConnectionBias::SetReferenceCurrent, &fBias)))
    718             ("");
    719 
    720         AddEvent("APPLY_REFERENCE_VOLTAGE", kStateConnected)
    721             (Wrapper(bind(&ConnectionBias::ApplyReferenceVoltage, &fBias)))
    722             ("");
    723 
    724         AddEvent("ADAPT_VOLTAGES", kStateConnected)
    725             (Wrapper(bind(&ConnectionBias::AdaptVoltages, &fBias)))
    726             ("");
    727 
    728         AddEvent("PRINT", kStateConnected)
     1213
     1214        T::AddEvent("REQUEST_STATUS", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1215            (Wrapper(bind(&ConnectionBias::ReadAllChannels, &fBias, false)))
     1216            ("");
     1217
     1218        T::AddEvent("RESET_OVER_CURRENT_STATUS", ConnectionBias::kConnected)
     1219            (Wrapper(bind(&ConnectionBias::OverCurrentReset, &fBias)))
     1220            ("");
     1221
     1222
     1223
     1224        T::AddEvent("SET_GLOBAL_VOLTAGE", "F:1", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1225            (bind(&StateMachineBias::SetGlobalVolt, this, placeholders::_1))
     1226            ("");
     1227
     1228        T::AddEvent("SET_GLOBAL_DAC", "S:1", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1229            (bind(&StateMachineBias::SetGlobalDac, this, placeholders::_1))
     1230            ("");
     1231
     1232        T::AddEvent("SET_CHANNEL_VOLTAGE", "S:1;F:1", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1233            (bind(&StateMachineBias::SetChannelVolt, this, placeholders::_1))
     1234            ("");
     1235
     1236        T::AddEvent("SET_CHANNEL_DAC", "S:1;S:1", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1237            (bind(&StateMachineBias::SetChannelDac, this, placeholders::_1))
     1238            ("");
     1239
     1240        T::AddEvent("SET_GAPD_REFERENCE_VOLTAGE", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1241            (Wrapper(bind(&ConnectionBias::SetGapdVoltage, &fBias)))
     1242            ("");
     1243
     1244        T::AddEvent("SET_ZERO_VOLTAGE", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1245            (Wrapper(bind(&ConnectionBias::SetZero, &fBias)))
     1246            ("");
     1247
     1248
     1249
     1250        T::AddEvent("STOP", ConnectionBias::kConnected, ConnectionBias::kRamping)
     1251            (Wrapper(bind(&ConnectionBias::RampStop, &fBias)))
     1252            ("");
     1253
     1254        T::AddEvent("START", ConnectionBias::kConnected)
     1255            (Wrapper(bind(&ConnectionBias::RampStart, &fBias)))
     1256            ("");
     1257
     1258
     1259
     1260        T::AddEvent("PRINT", ConnectionBias::kConnected, ConnectionBias::kRamping)
    7291261            (Wrapper(bind(&ConnectionBias::Print, &fBias)))
     1262            ("");
     1263
     1264
     1265        T::AddEvent("EXPERT_MODE", "B:1")
     1266            (bind(&StateMachineBias::SetExpertMode, this, placeholders::_1))
     1267            ("");
     1268
     1269        T::AddEvent("EXPERT_RESET", ConnectionBias::kExpertMode)
     1270            (Wrapper(bind(&ConnectionBias::ExpertReset, &fBias)))
     1271            ("");
     1272
     1273        T::AddEvent("EXPERT_SET_GLOBAL_VOLTAGE", "F:1", ConnectionBias::kExpertMode)
     1274            (bind(&StateMachineBias::ExpertSetGlobalVolt, this, placeholders::_1))
     1275            ("");
     1276
     1277        T::AddEvent("EXPERT_SET_GLOBAL_DAC", "S:1", ConnectionBias::kExpertMode)
     1278            (bind(&StateMachineBias::ExpertSetGlobalDac, this, placeholders::_1))
     1279            ("");
     1280
     1281        T::AddEvent("EXPERT_SET_CHANNEL_VOLTAGE", "S:1;F:1", ConnectionBias::kExpertMode)
     1282            (bind(&StateMachineBias::ExpertSetChannelVolt, this, placeholders::_1))
     1283            ("");
     1284
     1285        T::AddEvent("EXPERT_SET_CHANNEL_DAC", "S:1;S:1", ConnectionBias::kExpertMode)
     1286            (bind(&StateMachineBias::ExpertSetChannelDac, this, placeholders::_1))
    7301287            ("");
    7311288    }
     
    7371294        fBias.SetEndpoint(conf.Get<string>("dev"));
    7381295        T::Message("Setting device to "+fBias.URL());
     1296
     1297        const uint16_t step = conf.Get<uint16_t>("ramp-step");
     1298        const uint16_t time = conf.Get<uint16_t>("ramp-time");
     1299
     1300        if (step>230) // 5V
     1301        {
     1302            T::Error("ramp-step exceeds allowed range.");
     1303            return 1;
     1304        }
     1305        if (time>10000) // 5V
     1306        {
     1307            T::Error("ramp-time exceeds allowed range.");
     1308            return 2;
     1309        }
     1310
     1311        fBias.SetRampStep(step);
     1312        fBias.SetRampTime(time);
    7391313
    7401314        // --------------------------------------------------------------------------
     
    7701344            {
    7711345                T::Error("Invalid board/channel read from FACTmapV5.txt.");
    772                 return 1;
     1346                return 3;
    7731347            }
    7741348
     
    7801354        {
    7811355            T::Error("Reading reference voltages from FACTmapV5.txt failed.");
    782             return 2;
    783         }
    784 
    785         if (!fBias.SetReferenceVoltage(vec))
     1356            return 4;
     1357        }
     1358
     1359        if (!fBias.SetNewGapdVoltage(vec))
    7861360        {
    7871361            T::Error("Setting reference voltages failed.");
    788             return 3;
     1362            return 5;
    7891363        }
    7901364
     
    8131387        ("no-dim,d",      po_bool(),  "Disable dim services")
    8141388        ("dev",           var<string>("FTE00FOH"),  "Device address of USB port to bias-power supply")
    815         ("quiet,q",       po_bool(),  "Disable printing contents of all received messages (except dynamic data) in clear text.")
     1389        ("quiet,q",       po_bool(),        "Disable printing contents of all received messages (except dynamic data) in clear text.")
     1390        ("ramp-time",     var<uint16_t>(),  "")
     1391        ("ramp-step",     var<uint16_t>(),  "")
     1392        ("ramp-volt",     var<float>(),     "")
    8161393        ;
    8171394
Note: See TracChangeset for help on using the changeset viewer.