/**************************************************************\ Bias feedback Oliver Grimm, July 2010 \**************************************************************/ #include "Feedback.h" #include "PixelMap.h" #define PIXMAP_LOCATION "../config/PixelMap.txt" static const char* FBState_Description[] = { "Feedback off", "Feedback active", "Feedback acquiring new targets", "Feedback measuring response with first voltage", "Feedback measuring response with second voltage" }; static const struct CL_Struct { const char *Name; void (Feedback::*CommandPointer)(); const char *Parameters; const char *Help; } CommandList[] = {{"mode", &Feedback::cmd_mode, "[off|active|target]", "Set or get feedback mode"}, {"average", &Feedback::cmd_average, "[n]", "Set ot get number of averages for feedback"}, {"gain", &Feedback::cmd_gain, "[gain]", "Set ot get feedback gain"}, {"target", &Feedback::cmd_target, "[pixel id]", "Set or get target value"}, {"response", &Feedback::cmd_response, "[voltage]", "Start or get response measurement"}, {"clear", &Feedback::cmd_clear, "", "Clear feedback signals"}, {"data", &Feedback::cmd_data, "", "New feedback signals"}, {"help", &Feedback::cmd_help, "", "Print help"}, {"exit", &Feedback::cmd_exit, "", "Exit program"}}; using namespace std; // ----- Constructor: Initialise feedback Feedback::Feedback(): EvidenceServer(SERVER_NAME) { PixMap = new PixelMap(PIXMAP_LOCATION, false); TimeBarrier = 0; // DIM console service used in PrintMessage() ConsoleText = NULL; ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) ""); // Get pixel ID table fIDTable = Tokenize(GetConfig("IDTable"), " \t"); Multiplicity = new unsigned int [fIDTable.size()]; multiset A; char *Buf; for (unsigned int i=0; iPixel_to_HVboard(fIDTable[i]), PixMap->Pixel_to_HVchain(fIDTable[i]), PixMap->Pixel_to_HVchannel(fIDTable[i])) == -1) Message(FATAL, "asprintf() failed"); A.insert(Buf); free(Buf); } for (unsigned int i=0; iPixel_to_HVboard(fIDTable[i]), PixMap->Pixel_to_HVchain(fIDTable[i]), PixMap->Pixel_to_HVchannel(fIDTable[i])) == -1) Message(FATAL, "asprintf() failed"); Multiplicity[i] = A.count(Buf); free(Buf); } // Initialise with zero content ??? Average = new float [fIDTable.size()]; Sigma = new float [fIDTable.size()]; Response = new float [fIDTable.size()]; Target = new float [fIDTable.size()]; Buffer = new float [fIDTable.size()]; DIMAverage = new float [fIDTable.size()]; DIMSigma = new float [fIDTable.size()]; // Get remaing configuration data fDefaultNumAverage = atoi(GetConfig("DefaultNumAverage").c_str()); vector Token = Tokenize(GetConfig("DefaultResponse"), " \t"); for (unsigned int i=0; i< Token.size(); i++) { if (i < fIDTable.size()) Response[i] = (float) atof(Token[i].c_str()); } Token = Tokenize(GetConfig("DefaultTarget"), " \t"); for (unsigned int i=0; i=0) NumAverages = atoi(Parameter[1].c_str()); else PrintUsage(); } // ----- Set/get feedback gain void Feedback::cmd_gain() { if (Parameter.size() == 2) Gain = atof(Parameter[1].c_str()); PrintMessage("Feedback gain is %.2f\n", Gain); } // ----- Set/get target value void Feedback::cmd_target() { if (Parameter.size() == 1) { for (unsigned int i=0; iupdateService(); return; } for (unsigned int i=0; iupdateService(); return; } } PrintMessage("Invalid board, chip or channel number.\n"); } // ----- Start response measurement void Feedback::cmd_response() { if (Parameter.size() == 1) { for (unsigned int i=0; igetTimestamp() < TimeBarrier) return; TimeBarrier = 0; // Calculate average signal for (unsigned int i=0; i 2) { LastServiceUpdate = time(NULL); CountService->updateService(); } // Check if acquired number of event requires action if (++Count 0.1) Correction = fabs(Correction)/Correction*0.1; // Limit changes to 100 mV if (Correction==0 || Target[i]==0) break; // Add voltage change command if not too noisy if(fabs(Average[i]) > 2*Sigma[i]) { Cmd << fIDTable[i] << " " << std::showpos << Correction/Multiplicity[i] << " "; } break; case Targets: // Take average as new targets Target[i] = Average[i]; break; case ResponseFirst: // First point of response measurement done Buffer[i] = Average[i]; Cmd << fIDTable[i] << " " << std::showpos << DiffVoltage/Multiplicity[i] << " "; break; case ResponseSecond: // Determine response from signal variation if (Buffer[i] == Average[i]) { PrintMessage("Warning, response singular for pixel %s\n", fIDTable[i].c_str()); Response[i] = 0; } else Response[i] = DiffVoltage/(Buffer[i] - Average[i]); Cmd << fIDTable[i] << " " << std::showpos << -DiffVoltage/2/Multiplicity[i] << " "; break; default: break; // to suppress warning abount not handled enumeration value } } // for() // Update DIM service FeedbackAverage->updateService(); FeedbackSigma->updateService(); // Send command (non-blocking since in handler thread) if (!Cmd.str().empty()) { DimClient::sendCommandNB("Bias/Command", (char *) ("hv "+Cmd.str()).c_str()); } switch (FBMode) { case Targets: FeedbackTarget->updateService(); PrintMessage("New targets set, switching off\n"); SetFBMode(Off); break; case ResponseFirst: SetFBMode(ResponseSecond); PrintMessage("Increasing voltages by %f for response measurement, acquiring data\n", DiffVoltage); break; case ResponseSecond: FeedbackResponse->updateService(); PrintMessage("Response measurements finished, original voltages set, switching off\n"); SetFBMode(Off); break; default: break; // to suppress warning abount not handled enumeration value } ClearAverages(); return; } // ----- Print help void Feedback::cmd_help() { char Buffer[BUF_LENGTH]; for(unsigned int i=0; iupdateService(); } // ----- Set feedback mode and clear averages void Feedback::SetFBMode(FBState Mode) { FBMode = Mode; if (Mode != ResponseFirst) PrintMessage("%s\n", FBState_Description[FBMode]); else PrintMessage("%s (voltage difference %.3f)\n", FBState_Description[FBMode], DiffVoltage); ClearAverages(); // Update state service State.State = FBMode; strncpy(State.Text, FBState_Description[FBMode], sizeof(State.Text)); FeedbackState->updateService(&State, sizeof(State)); // Reject feedback signals received earlier than this time TimeBarrier = time(NULL) + 2; } // ----- Measure response matrix void Feedback::MeasureResponse(float U) { std::stringstream Cmd; if (U == 0) { PrintMessage("Error, voltage difference must be non-zero.\n"); return; } // Build command for (unsigned int i=0; i0 && Text[strlen(Text)-1]=='\n') printf("\r%sCmd> ", Text); // New prompt else printf("%s", Text); fflush(stdout); // Send to DIM text service ConsoleOut->updateService(Text); // Free old text if (ConsoleText != Error) free(ConsoleText); ConsoleText = Text; } // ----- DIM command handler void Feedback::commandHandler() { string Command = ToString("C", getCommand()->getData(), getCommand()->getSize()); // Parse command into tokens Parameter.clear(); Parameter = Tokenize(Command, " \t"); if (Parameter.empty()) return; // Search for command for (unsigned int Count=0; Count*CommandList[Count].CommandPointer)(); return; } } // Command not found PrintMessage("Unknown command '%s'\n", Command.c_str()); } // ----- Check if two strings match (min 1 character must match) bool Feedback::Match(string str, string cmd) { return strncasecmp(str.c_str(),cmd.c_str(),strlen(str.c_str())==0 ? 1:strlen(str.c_str())) ? false:true; } // ================ // Main program // ================ int main() { char *Command; system("clear"); printf("\n*** Bias feedback (built %s, %s, revision %s) *** \n\n",__DATE__, __TIME__, REVISION); // Readline library uses getc() (allows interruption by signal) rl_getc_function = getc; // Construct main instance (static ensures destructor is called with exit()) static Feedback M; // Command loop while (!M.ExitRequest) { // Read Command Command = readline("\rCmd> "); if (Command == NULL) continue; if(strlen(Command)>0) add_history(Command); // Process command DimClient::sendCommand(SERVER_NAME"/Command", Command); free(Command); } }