source: fact/Feedback/Feedback.cc@ 17038

Last change on this file since 17038 was 11205, checked in by ogrimm, 13 years ago
Adaptions to allow compilation on Ubuntu
File size: 13.8 KB
Line 
1/**************************************************************\
2
3 Bias feedback
4
5 Oliver Grimm, July 2010
6
7\**************************************************************/
8
9
10#include "Feedback.h"
11#include "PixelMap.h"
12
13static const char* FBState_Description[] = {
14 "Feedback off",
15 "Feedback active",
16 "Feedback acquiring new targets",
17 "Feedback measuring response with first voltage",
18 "Feedback measuring response with second voltage"
19};
20
21static const struct CL_Struct { const char *Name;
22 void (Feedback::*CommandPointer)();
23 const char *Parameters;
24 const char *Help;
25 } CommandList[] =
26 {{"mode", &Feedback::cmd_mode, "[off|active|target]", "Set or get feedback mode"},
27 {"average", &Feedback::cmd_average, "[n]", "Set ot get number of averages for feedback"},
28 {"gain", &Feedback::cmd_gain, "[gain]", "Set ot get feedback gain"},
29 {"target", &Feedback::cmd_target, "[pixel id]", "Set or get target value"},
30 {"response", &Feedback::cmd_response, "[voltage]", "Start or get response measurement"},
31 {"clear", &Feedback::cmd_clear, "", "Clear feedback signals"},
32 {"data", &Feedback::cmd_data, "", "New feedback signals"},
33 {"help", &Feedback::cmd_help, "", "Print help"},
34 {"exit", &Feedback::cmd_exit, "", "Exit program"}};
35
36using namespace std;
37
38
39// ----- Constructor: Initialise feedback
40Feedback::Feedback(): EvidenceServer(SERVER_NAME) {
41
42 // Make RPC to get pixelmap
43 DimRpcInfo RPC((char *) "ConfigRequest", (char *) "");
44 RPC.setData((char *) "Misc PixelMap");
45
46 PixMap = new PixelMap(std::string(RPC.getString(), RPC.getSize()));
47 TimeBarrier = 0;
48
49 // DIM console service used in PrintMessage()
50 ConsoleText = NULL;
51 ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
52
53 // Get pixel ID table
54 fIDTable = Tokenize(GetConfig("IDTable"), " \t");
55 Multiplicity = new unsigned int [fIDTable.size()];
56
57 // Determine multiplicity of bias to pixel connection
58 std::vector<unsigned int> A;
59 for (unsigned int i=0; i<fIDTable.size(); i++) {
60 A = PixMap->HV_to_Pixel(PixMap->Pixel_to_HVcrate(atoi(fIDTable[i].c_str())), PixMap->Pixel_to_HVboard(atoi(fIDTable[i].c_str())), PixMap->Pixel_to_HVchannel(atoi(fIDTable[i].c_str())));
61 Multiplicity[i] = A.size();
62 }
63
64 // Initialise with zero content ???
65 Average = new float [fIDTable.size()];
66 Sigma = new float [fIDTable.size()];
67 Response = new float [fIDTable.size()];
68 Target = new float [fIDTable.size()];
69 Buffer = new float [fIDTable.size()];
70
71 DIMAverage = new float [fIDTable.size()];
72 DIMSigma = new float [fIDTable.size()];
73
74 // Get remaing configuration data
75 fDefaultNumAverage = atoi(GetConfig("DefaultNumAverage").c_str());
76
77 vector<string> Token = Tokenize(GetConfig("DefaultResponse"), " \t");
78 for (unsigned int i=0; i< Token.size(); i++) {
79 if (i < fIDTable.size()) Response[i] = (float) atof(Token[i].c_str());
80 }
81
82 Token = Tokenize(GetConfig("DefaultTarget"), " \t");
83 for (unsigned int i=0; i<Token.size(); i++) {
84 if (i < fIDTable.size()) Target[i] = (float) atof(Token[i].c_str());
85 }
86
87 // Provide DIM services
88 FeedbackAverage = new DimService (SERVER_NAME"/Average", "F", DIMAverage, fIDTable.size() * sizeof(float));
89 FeedbackSigma = new DimService (SERVER_NAME"/Sigma", "F", DIMSigma, fIDTable.size() * sizeof(float));
90 FeedbackResponse = new DimService (SERVER_NAME"/Response", "F", Response, fIDTable.size() * sizeof(float));
91 FeedbackTarget = new DimService (SERVER_NAME"/Target", "F", Target, fIDTable.size() * sizeof(float));
92 CountService = new DimService (SERVER_NAME"/Count", Count);
93 FeedbackState = new DimService (SERVER_NAME"/State", "I:1;C", NULL, 0);
94
95 // Initial state
96 Gain = atof(GetConfig("DefaultGain").c_str());
97 SetFBMode(Off);
98 NumAverages = fDefaultNumAverage;
99 LastServiceUpdate = 0;
100
101 // Install DIM command (after all initialized)
102 Command = new DimCommand((char *) SERVER_NAME"/Command", (char *) "C", this);
103}
104
105
106// ----- Destructor
107Feedback::~Feedback() {
108
109 delete Command;
110 delete FeedbackState;
111 delete CountService;
112 delete FeedbackAverage;
113 delete FeedbackSigma;
114 delete FeedbackResponse;
115 delete FeedbackTarget;
116
117 delete[] Average; delete[] Response;
118 delete[] DIMAverage; delete[] DIMSigma;
119 delete[] Sigma; delete[] Target;
120 delete[] Buffer; delete[] Multiplicity;
121 delete PixMap;
122
123 delete ConsoleOut;
124 free(ConsoleText);
125}
126
127
128// ----- Set/get mode of feedback
129void Feedback::cmd_mode() {
130
131 if (Match(Parameter[1], "off")) SetFBMode(Off);
132 else if (Match(Parameter[1], "active")) SetFBMode(Active);
133 else if (Match(Parameter[1], "targets")) SetFBMode(Targets);
134 else PrintMessage("%s.\n", FBState_Description[FBMode]);
135}
136
137
138// ----- Set/get current number of events
139void Feedback::cmd_average() {
140
141 if (Parameter.size() == 1) {
142 PrintMessage("Current feedback events: %u (acting when %u events reached)\n", Count, NumAverages);
143 }
144 else if (atoi(Parameter[1].c_str())>=0) NumAverages = atoi(Parameter[1].c_str());
145 else PrintUsage();
146}
147
148
149// ----- Set/get feedback gain
150void Feedback::cmd_gain() {
151
152 if (Parameter.size() == 2) Gain = atof(Parameter[1].c_str());
153 PrintMessage("Feedback gain is %.2f\n", Gain);
154}
155
156
157// ----- Set/get target value
158void Feedback::cmd_target() {
159
160 if (Parameter.size() == 1) {
161 for (unsigned int i=0; i<fIDTable.size(); i++) {
162 PrintMessage("%s: %.2f ", fIDTable[i].c_str(), Target[i]);
163 if (i%5 == 4) PrintMessage("\n\r");
164 }
165 PrintMessage("\n");
166 return;
167 }
168
169 if (Parameter.size() != 3) {
170 PrintUsage();
171 return;
172 }
173
174 if (Match(Parameter[1], "all")) {
175 for (unsigned int i=0; i<fIDTable.size(); i++) {
176 Target[i] = atof(Parameter[2].c_str());
177 }
178 FeedbackTarget->updateService();
179 return;
180 }
181
182 for (unsigned int i=0; i<fIDTable.size(); i++) {
183 if (Match(Parameter[1], fIDTable[i])) {
184 Target[i] = atof(Parameter[2].c_str());
185 FeedbackTarget->updateService();
186 return;
187 }
188 }
189
190 PrintMessage("Invalid board, chip or channel number.\n");
191}
192
193
194// ----- Start response measurement
195void Feedback::cmd_response() {
196
197 if (Parameter.size() == 1) {
198 for (unsigned int i=0; i<fIDTable.size(); i++) {
199 PrintMessage("%s: %.2f ", fIDTable[i].c_str(), Response[i]);
200 if (i%5 == 4) PrintMessage("\n\r");
201 }
202 PrintMessage("\n");
203 }
204 else if (atof(Parameter[1].c_str()) != 0) MeasureResponse(atof(Parameter[1].c_str()));
205 else PrintUsage();
206}
207
208
209// ----- Clear accumulated averages
210void Feedback::cmd_clear() {
211
212 ClearAverages();
213}
214
215
216// ----- Accumulate feedback data and calculate voltage change if required number of events reached.
217void Feedback::cmd_data() {
218
219 float Correction;
220
221 // Reject data if feedback off or timestamp too early
222 if (FBMode == Off || getCommand()->getTimestamp() < TimeBarrier) return;
223 TimeBarrier = 0;
224
225 // Calculate average signal
226 for (unsigned int i=0; i<Parameter.size()-1 && i<fIDTable.size(); i++) {
227 Average[i] += atof(Parameter[i+1].c_str());
228 Sigma[i] += pow(atof(Parameter[i+1].c_str()), 2);
229 }
230
231 // Update DIM count service regularly
232 if (time(NULL)-LastServiceUpdate > 2) {
233 LastServiceUpdate = time(NULL);
234 CountService->updateService();
235 }
236
237 // Check if acquired number of event requires action
238 if (++Count<NumAverages) return;
239
240 // Feedback action
241 std::stringstream Cmd;
242
243 for (unsigned int i=0; i<fIDTable.size(); i++) {
244 // Calculate average
245 Average[i] /= Count;
246 Sigma[i] = sqrt(Sigma[i]/Count - pow(Average[i],2))/sqrt(Count);
247 DIMAverage[i] = Average[i];
248 DIMSigma[i] = Sigma[i];
249
250 switch (FBMode) {
251 case Active:
252 // Determine correction from response maxtrix and change voltages
253 Correction = -(Target[i] - Average[i])*Response[i]*Gain;
254 // Limit voltage steps
255 if (fabs(Correction) > 0.1) Correction = fabs(Correction)/Correction*0.1; // Limit changes to 100 mV
256 if (Correction==0 || Target[i]==0) break;
257 // Add voltage change command if not too noisy
258 if(fabs(Average[i]) > 2*Sigma[i]) {
259 Cmd << fIDTable[i] << " " << std::showpos << Correction/Multiplicity[i] << " ";
260 }
261 break;
262
263 case Targets: // Take average as new targets
264 Target[i] = Average[i];
265 break;
266
267 case ResponseFirst: // First point of response measurement done
268 Buffer[i] = Average[i];
269 Cmd << fIDTable[i] << " " << std::showpos << DiffVoltage/Multiplicity[i] << " ";
270 break;
271
272 case ResponseSecond: // Determine response from signal variation
273 if (Buffer[i] == Average[i]) {
274 PrintMessage("Warning, response singular for pixel %s\n", fIDTable[i].c_str());
275 Response[i] = 0;
276 }
277 else Response[i] = DiffVoltage/(Buffer[i] - Average[i]);
278
279 Cmd << fIDTable[i] << " " << std::showpos << -DiffVoltage/2/Multiplicity[i] << " ";
280 break;
281
282 default: break; // to suppress warning abount not handled enumeration value
283 }
284 } // for()
285
286 // Update DIM service
287 FeedbackAverage->updateService();
288 FeedbackSigma->updateService();
289
290 // Send command (non-blocking since in handler thread)
291 if (!Cmd.str().empty()) {
292 DimClient::sendCommandNB("Bias/Command", (char *) ("pixel "+Cmd.str()).c_str());
293 }
294
295 switch (FBMode) {
296 case Targets:
297 FeedbackTarget->updateService();
298 PrintMessage("New targets set, switching off\n");
299 SetFBMode(Off);
300 break;
301 case ResponseFirst:
302 SetFBMode(ResponseSecond);
303 PrintMessage("Increasing voltages by %f for response measurement, acquiring data\n", DiffVoltage);
304 break;
305 case ResponseSecond:
306 FeedbackResponse->updateService();
307 PrintMessage("Response measurements finished, original voltages set, switching off\n");
308 SetFBMode(Off);
309 break;
310 default: break; // to suppress warning abount not handled enumeration value
311 }
312 ClearAverages();
313
314 return;
315}
316
317
318// ----- Print help
319void Feedback::cmd_help() {
320
321 char Buffer[BUF_LENGTH];
322
323 for(unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
324 snprintf(Buffer, sizeof(Buffer), "%s %s", CommandList[i].Name, CommandList[i].Parameters);
325 PrintMessage("%-28s%s\n", Buffer, CommandList[i].Help);
326 }
327}
328
329
330// ----- Exit programm
331void Feedback::cmd_exit() {
332
333 ExitRequest = true;
334}
335
336
337// ----- Clear average values and event counter
338void Feedback::ClearAverages() {
339
340 for (unsigned int i=0; i<fIDTable.size(); i++) {
341 Average[i] = 0.0;
342 Sigma[i] = 0.0;
343 }
344 Count = 0;
345 CountService->updateService();
346}
347
348
349// ----- Set feedback mode and clear averages
350void Feedback::SetFBMode(FBState Mode) {
351
352 FBMode = Mode;
353 if (Mode != ResponseFirst) PrintMessage("%s\n", FBState_Description[FBMode]);
354 else PrintMessage("%s (voltage difference %.3f)\n", FBState_Description[FBMode], DiffVoltage);
355 ClearAverages();
356
357 // Update state service
358 State.State = FBMode;
359 strncpy(State.Text, FBState_Description[FBMode], sizeof(State.Text));
360 FeedbackState->updateService(&State, sizeof(State));
361
362 // Reject feedback signals received earlier than this time
363 TimeBarrier = time(NULL) + 2;
364}
365
366
367// ----- Measure response matrix
368void Feedback::MeasureResponse(float U) {
369
370 std::stringstream Cmd;
371
372 if (U == 0) {
373 PrintMessage("Error, voltage difference must be non-zero.\n");
374 return;
375 }
376
377 // Build command
378 for (unsigned int i=0; i<fIDTable.size(); i++) {
379 Cmd << fIDTable[i] << " " << std::showpos << -U/2/Multiplicity[i] << " ";
380 }
381
382 // Send command
383 if (!Cmd.str().empty()) {
384 DimClient::sendCommand("Bias/Command", ("pixel "+Cmd.str()).c_str());
385 }
386
387 DiffVoltage = U;
388 SetFBMode(ResponseFirst);
389 PrintMessage("Feedback: Decreasing voltages by %f for response measurement, acquiring data.\n",DiffVoltage/2);
390}
391
392
393// ----- Print usage text for command
394void Feedback::PrintUsage() {
395
396 for (unsigned int i=0; i<sizeof(CommandList)/sizeof(CL_Struct); i++) {
397 if (Match(Parameter[0], CommandList[Count].Name)) {
398 PrintMessage("Usage: %s %s\n", Parameter[0].c_str(), CommandList[Count].Parameters);
399 }
400 }
401}
402
403
404// ----- Print message to console only
405void Feedback::PrintMessage(const char *Format, ...) {
406
407 static char Error[] = "vasprintf() failed in PrintMessage()";
408 char *Text;
409
410 // Evaluate arguments
411 va_list ArgumentPointer;
412 va_start(ArgumentPointer, Format);
413 if (vasprintf(&Text, Format, ArgumentPointer) == -1) Text = Error;
414 va_end(ArgumentPointer);
415
416 // Print to console
417 if(strlen(Text)>0 && Text[strlen(Text)-1]=='\n') printf("\r%sCmd> ", Text); // New prompt
418 else printf("%s", Text);
419 fflush(stdout);
420
421 // Send to DIM text service
422 ConsoleOut->updateService(Text);
423
424 // Free old text
425 if (ConsoleText != Error) free(ConsoleText);
426 ConsoleText = Text;
427}
428
429
430// ----- DIM command handler
431void Feedback::commandHandler() {
432
433 string Command = ToString((char *) "C", getCommand()->getData(), getCommand()->getSize());
434
435 // Parse command into tokens
436 Parameter.clear();
437 Parameter = Tokenize(Command, " \t");
438 if (Parameter.empty()) return;
439
440 // Search for command
441 for (unsigned int Count=0; Count<sizeof(CommandList)/sizeof(CL_Struct); Count++) {
442 if (Match(Parameter[0], CommandList[Count].Name)) {
443 (this->*CommandList[Count].CommandPointer)();
444 return;
445 }
446 }
447
448 // Command not found
449 PrintMessage("Unknown command '%s'\n", Command.c_str());
450}
451
452
453// ----- Check if two strings match (min 1 character must match)
454bool Feedback::Match(string str, string cmd) {
455 return strncasecmp(str.c_str(),cmd.c_str(),strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true;
456}
457
458
459// ================
460// Main program
461// ================
462
463int main() {
464
465 char *Command;
466
467 if (system("clear") == -1) printf("Error with system() call\n");
468 printf("\n*** Bias feedback (built %s, %s, revision %s) *** \n\n",__DATE__, __TIME__, REVISION);
469
470 // Readline library uses getc() (allows interruption by signal)
471 rl_getc_function = getc;
472
473 // Construct main instance (static ensures destructor is called with exit())
474 static Feedback M;
475
476 // Command loop
477 while (!M.ExitRequest) {
478 // Read Command
479 Command = readline("\rCmd> ");
480 if (Command == NULL) continue;
481 if(strlen(Command)>0) add_history(Command);
482
483 // Process command
484 DimClient::sendCommand(SERVER_NAME"/Command", Command);
485 free(Command);
486 }
487}
Note: See TracBrowser for help on using the repository browser.