Index: fact/BIASctrl/Crate.cc
===================================================================
--- fact/BIASctrl/Crate.cc	(revision 11915)
+++ fact/BIASctrl/Crate.cc	(revision 11919)
@@ -182,5 +182,8 @@
   funlockfile(File);
 
-  if (ErrorCount > MAX_ERR_COUNT) Disabled = true;
+  if (ErrorCount > MAX_ERR_COUNT) {
+  	m->Message(m->ERROR, "Crate %s has more than %d errors, disabled", Name, MAX_ERR_COUNT);   
+	Disabled = true;
+  }
 
   return Data;
@@ -224,5 +227,5 @@
   if (Data.size() != Buf.size()) return false;
 
-  // Evaluate data returned from crate
+  // Evaluate data returned from crate (1 count for current -> 1.22 uA)
   int Count = 0;
   for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
Index: fact/BIASctrl/History.txt
===================================================================
--- fact/BIASctrl/History.txt	(revision 11915)
+++ fact/BIASctrl/History.txt	(revision 11919)
@@ -20,2 +20,3 @@
 26/8/2011	Removed support for multiple crates. Crate name can be given as
 			command line argument.
+30/8/2011	Added basic calibration for current measurement.
Index: fact/BIASctrl/User.cc
===================================================================
--- fact/BIASctrl/User.cc	(revision 11915)
+++ fact/BIASctrl/User.cc	(revision 11919)
@@ -21,5 +21,8 @@
 	{"reset", &User::cmd_reset, 0, true, "", "Reset active crate"},
 	{"synch", &User::cmd_synch, 0, true, "", "Synchronize active crate"},
-	{"status", &User::cmd_status, 0, false, "[dac|current]", "Show status information (DAC values if requested)"},
+	{"voltage", &User::cmd_status, 0, false, "[dac]", "Show voltage setpoints"},
+	{"current", &User::cmd_status, 0, false, "", "Show currents"},
+	{"status", &User::cmd_status, 0, false, "[R|I0]", "Show status information"},	
+	{"calib", &User::cmd_calib, 1, true, "<V1 V2 Num|invalidate>", "Calibrate current measurement (linear fit between V1 and V2)"},
 	{"mode", &User::cmd_mode, 1, true, "<static|dynamic>", "Set voltage stabilization mode (experimental)"},
 	{"load", &User::cmd_load, 1, true, "<file>", "Load and set bias settings from file"},
@@ -34,4 +37,6 @@
 User::User(string Board): EvidenceServer(SERVER_NAME) {
 
+  vector<string> Text;
+
   MainThread = pthread_self();
 
@@ -39,4 +44,8 @@
   ConsoleText = NULL;
   ConsoleOut = new DimService(SERVER_NAME"/ConsoleOut", (char *) "");
+
+  // Initialize current calibration constants
+  R.resize(MAX_NUM_BOARDS*NUM_CHANNELS, numeric_limits<double>::infinity());
+  I0.resize(MAX_NUM_BOARDS*NUM_CHANNELS, 0);
 
   // Get/initialize configuration data
@@ -47,8 +56,18 @@
   GetConfig("RampSpeed");
   GetConfig("UpdatePeriod");
-  vector<string> Text = Tokenize(GetConfig("DefaultVoltage", ""), " \t");
-  
+
+  Text = Tokenize(GetConfig("DefaultVoltage", ""), " \t"); 
   for (unsigned int i=0; i<Text.size(); i++) {
 	DefaultVoltage.push_back(atof(Text[i].c_str()));
+  }    
+
+  Text = Tokenize(GetConfig("Calibration_R"), " \t"); 
+  for (unsigned int i=0; i<Text.size() && i<R.size(); i++) {
+	R[i] = atof(Text[i].c_str())/1000.0;
+  }
+
+  Text = Tokenize(GetConfig("Calibration_I0"), " \t"); 
+  for (unsigned int i=0; i<Text.size() && i<I0.size(); i++) {
+	I0[i] = atof(Text[i].c_str());
   }
 
@@ -389,7 +408,90 @@
 
 //
+// Calibrate current measurement
+//
+void User::cmd_calib() {
+
+  map<unsigned int, double> Voltages, Initial, Current[2];
+  int Errors, Num;
+  double Volt[2];
+
+  // Clear current calibration values?
+  if (Match(Parameter[1], "invalidate")) {
+	PrintMessage("Current calibration invalidated\n");
+	R.assign(MAX_NUM_BOARDS*NUM_CHANNELS, numeric_limits<double>::infinity());
+	I0.assign(MAX_NUM_BOARDS*NUM_CHANNELS, 0);
+	return;
+  }
+
+  // Check number of parameters and convert
+  if (Parameter.size() != 4) {
+	PrintMessage("Error: Number of parameters incorrect\n");
+	return;
+  }
+
+  if (!ConvertToDouble(Parameter[1], &Volt[0]) || !ConvertToDouble(Parameter[2], &Volt[1])) {
+    PrintMessage("Error: Wrong number format for voltages\n");
+	return;
+  }
+
+  if (!ConvertToInt(Parameter[3], &Num)) {
+    PrintMessage("Error: Wrong number format for number of iterations\n");
+	return;
+  }
+
+  // Check if infinity can be represented for double
+  if (!numeric_limits<double>::has_infinity) {
+	PrintMessage("Cannot perform calibration, double cannot represent infinity\n");
+	return;
+  }
+
+  // Save initial voltages
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) Initial[i] = Dev->GetVoltage(i);
+
+  // Make current measurements at given voltages
+  for (unsigned int Round=0; Round<2; Round++) {
+	// Set voltage
+	for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) Voltages[i] = Volt[Round];
+
+	if ((Errors = RampVoltages(Voltages)) != 0) {
+	  PrintMessage("%d errors occurred while ramping to %.2f V\n", Errors, Volt[Round]);
+	  return;
+	}
+	else PrintMessage("Ramped all channels to %.2f V\n", Volt[Round]);
+
+	// Read currenty repeatably
+	for (int Count=0; Count<Num; Count++) {
+	  if (Count % 20 == 0) PrintMessage("Reading current iteration %d   \r", Count);
+	  if (!Dev->ReadAll()) {
+		PrintMessage("\nError from ReadAll()\n");
+		return;
+	  }
+	  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
+		Current[Round][i] += Dev->GetCurrent(i)/Num;
+	  }
+	}
+  } // for()
+
+
+  // Set initial voltages
+  if ((Errors = RampVoltages(Initial)) != 0) {
+	PrintMessage("%d errors occurred while ramping back to inital voltages\n", Errors);
+	return;
+  }
+  else PrintMessage("Ramped all channels back to inital voltages\n");
+
+  // Calculate calibration constants (R in MOhm)
+  for (unsigned int i=0; i<MAX_NUM_BOARDS*NUM_CHANNELS; i++) {
+    R[i] = (Volt[1] - Volt[0]) / (Current[1][i]-Current[0][i]);
+	I0[i] = Current[0][i] - Volt[0]/R[i];
+  }
+}
+
+//
 // Print status
 //
 void User::cmd_status() {
+
+  enum {M_V,M_DAC,M_I,M_R,M_I0,M_notset} M = M_notset;
 
   // Overview information
@@ -414,14 +516,30 @@
 
   // Voltage or current list
-  if (Parameter.size() == 1) PrintMessage("Channel voltages (in V)");
-  else if (Match(Parameter[1], "dac")) PrintMessage("Channel voltages (in DAC values)");
-  else PrintMessage("Channel currents (in uA)");
+  if (Match(Parameter[0], "voltage")) {
+	if (Parameter.size() == 1) M = M_V;
+	else M = M_DAC;
+  }
+  else if (Match(Parameter[0], "current")) M = M_I;
+  else if (Parameter.size() == 2) {
+	if (Match(Parameter[1], "R")) M = M_R;
+	if (Match(Parameter[1], "I0")) M = M_I0;
+  }
+
+  if (M == M_notset) return;
+  if (M == M_V) PrintMessage("Channel voltages (in V)");
+  if (M == M_DAC) PrintMessage("Channel voltages (in DAC values)");
+  if (M == M_R) PrintMessage("Channel internal resistance  (in kOhm)");
+  if (M == M_I0) PrintMessage("Channel current offset (in uA)");
+  if (M == M_I) PrintMessage("Channel currents (in uA)");
 
   for (unsigned int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
 	if (j%12 == 0) PrintMessage("\n%3.1d:  ", j);
-	if (!Dev->Present[j]) PrintMessage("  -   ");
-    else if (Parameter.size() == 1) PrintMessage("%#5.2f", Dev->GetVoltage(j));
-	else if (Match(Parameter[1], "dac")) PrintMessage("%5d", Dev->GetDAC(j));
-	else PrintMessage("%#5.2f", Dev->GetCurrent(j));
+	if (!Dev->Present[j]) PrintMessage("    -");
+    else if (M == M_V) PrintMessage("%#5.2f", Dev->GetVoltage(j));
+	else if (M == M_DAC) PrintMessage("%5d", Dev->GetDAC(j));
+	else if (M == M_R) PrintMessage("%#5.2f", R[j]*1000);
+	else if (M == M_I0) PrintMessage("%#5.2f", I0[j]);
+	else if (M == M_I) PrintMessage("%#5.1f", Dev->GetCurrent(j) - Dev->GetVoltage(j)/R[j] - I0[j]); 
+
 	// Print overcurrent marker
 	PrintMessage("%s ", Dev->OC[j] ? "*":" ");
Index: fact/BIASctrl/User.h
===================================================================
--- fact/BIASctrl/User.h	(revision 11915)
+++ fact/BIASctrl/User.h	(revision 11919)
@@ -33,5 +33,6 @@
 	class Crate *Dev;
 	std::vector<double> DefaultVoltage;
-
+	std::vector<double> R, I0;
+	
 	void commandHandler();
 
@@ -60,5 +61,5 @@
 	void cmd_exit();	void cmd_reset();
 	void cmd_help();	void cmd_mode();
-	void cmd_shell();
+	void cmd_shell();	void cmd_calib();
 };
 
