Changeset 14325
- Timestamp:
- 08/07/12 23:12:23 (12 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/FACT++/src/agilentctrl.cc
r14324 r14325 59 59 } 60 60 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 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 71 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) 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 } 111 private: 112 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 { 71 128 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 85 140 { 86 141 ostringstream str; 87 str << " Write timeout of " << URL() << ": " << error.message() << " (" << error << ")";// << endl;142 str << "Reading from " << URL() << ": " << err.message() << " (" << err << ")";// << endl; 88 143 Error(str); 89 90 PostClose(false);91 return;92 144 } 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 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 } 238 239 public: 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()) 95 269 { 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")); 100 271 } 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 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 { 111 301 private: 112 302 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 } 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 238 315 239 316 public: 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 } 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 } 325 325 }; 326 326 … … 331 331 { 332 332 private: 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 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 379 379 return State::kDisconnected; 380 380 }
Note:
See TracChangeset
for help on using the changeset viewer.