Index: /fact/BIASctrl/Crate.cc
===================================================================
--- /fact/BIASctrl/Crate.cc	(revision 10058)
+++ /fact/BIASctrl/Crate.cc	(revision 10059)
@@ -4,4 +4,5 @@
                 
 \********************************************************************/
+#include <utility>
 
 #include "Crate.h"
@@ -29,4 +30,5 @@
 	for (int j=0; j<NUM_CHANNELS; j++) {
 	  OC[i][j] = false;
+	  Present[i][j] = false;
 	  Current[i][j] = 0;
 	}
@@ -102,5 +104,5 @@
 //
 // Returns: 0 error, 1 success, -1 time-out exceeded
-vector<char> Crate::Communicate(unsigned char* wbuf, int Bytes) {
+vector<char> Crate::Communicate(string Buf) {
 
   int N;
@@ -114,7 +116,7 @@
   
   // === Write data ===
-  if ((N = write(fDescriptor, wbuf, Bytes)) < Bytes) {
+  if ((N = write(fDescriptor, Buf.data(), Buf.size())) < (int) Buf.size()) {
     if (N == -1) m->Message(m->ERROR, "Could not write data to crate (%s)", strerror(errno));
-    else m->Message(m->ERROR, "Could write only %d of %d bytes to board", N, Bytes);
+    else m->Message(m->ERROR, "Could write only %d of %d bytes to board", N, Buf.size());
     ErrorCount++;
 	goto ExitCommunicate;
@@ -144,5 +146,5 @@
 	// Add data to buffer
 	for (int i=0; i<N; i++) Data.push_back(Buffer[i]);
-  } while(Data.size() < (unsigned int) Bytes);
+  } while(Data.size() < Buf.size());
   
   // === Check if multiple of three bytes were returned ===
@@ -175,9 +177,7 @@
 int Crate::SystemReset() {
   
-  unsigned char wbuf[] = {0,0,0};
-  vector<char> Data = Communicate(wbuf, 3);
-  
+  vector<char> Data = Communicate(string(3, 0));
+
   if (Data.size() == 3) {
-    ClearVoltageArrays();
     ErrorCount = 0;
 	return 1;
@@ -187,58 +187,28 @@
 
 //
-// Read channel status
-//
-int Crate::ReadChannel(unsigned int Board, unsigned int Channel) {
-  
-   // Check limits
-  if (Board > MAX_NUM_BOARDS) {
-    m->PrintMessage("Error: Board number out of range\n"); 
-    return 0;
-  }
-  if (Channel > NUM_CHANNELS) {
-    m->PrintMessage("Error: Channel number out of range\n"); 
-    return 0;
-  }
-
-  // Execute command
-  unsigned char wbuf[] = {1<<5 | Board<<1 | (Channel&16)>>4, Channel<<4, 0}; 
-  vector<char> Data = Communicate(wbuf, 3);
-
-  if (Data.size() == 3) {
-	Current[Board][Channel] = Data[1] + (Data[0]&15)*256;
-	OC[Board][Channel] = Data[0] & 128;
-	ResetHit = Data[2] & 128;
-	if (Board==2 && Channel==19) OC[Board][Channel] = false;
-	return 1;
-  }
-  return Data[0];
-}
-
-
-//
 // Read all channels status
 //
 int Crate::ReadAll() {
 
-  unsigned char wbuf[3*MAX_NUM_BOARDS*NUM_CHANNELS];
-  int Count = 0;
+  string Buf;
 
   // Prepare command to read all channels
   for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
-	wbuf[Count++] = 1<<5 | i<<1 | (j&16)>>4;
-	wbuf[Count++] = j<<4;
-	wbuf[Count++] = 0;
+	Buf.push_back(1<<5 | i<<1 | (j&16)>>4);
+	Buf.push_back(j<<4);
+	Buf.push_back(0);
   }
   
   // Execute command
-  vector<char> Data = Communicate(wbuf, 3*MAX_NUM_BOARDS*NUM_CHANNELS);
+  vector<char> Data = Communicate(Buf);
     
-  if (Data.size() != 3*MAX_NUM_BOARDS*NUM_CHANNELS) return Data[0];
-
-  //Evaluate returned data
-  Count = 0;
+  if (Data.size() != Buf.size()) return Data[0];
+
+  // Evaluate data returned from crate
+  int Count = 0;
   for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
 	Current[i][j] = Data[Count+1] + (Data[Count]&15)*256;
 	OC[i][j] = Data[Count] & 128;
+	Present[i][j] = Data[Count+2] & 0x70 ? false : true;
 	ResetHit = Data[Count+2] & 128;
 	Count += 3;
@@ -259,6 +229,7 @@
 
   // Execute command
-  unsigned char wbuf[] = {1<<6 , SetPoint>>8, SetPoint};
-  vector<char> Data = Communicate(wbuf, 3);
+  string Buf;
+  Buf = (((Buf + char(1<<6)) + char(SetPoint>>8)) + char(SetPoint));
+  vector<char> Data = Communicate(Buf);
 
   if (Data.size() == 3) {
@@ -273,56 +244,28 @@
 
 
-// ***** Channel set *****
-int Crate::ChannelSet(int Board, int Channel, unsigned int SetPoint) {
-  
-  // Check limits
-  if (SetPoint > 0x0FFF) {
-    m->PrintMessage("Error: Voltage DAC value above 0x0FFF\n"); 
-    return 0;
-  }
-  if (Board > MAX_NUM_BOARDS) {
-    m->PrintMessage("Error: Board number out of range\n"); 
-    return 0;
-  }
-  if (Channel > NUM_CHANNELS) {
-    m->PrintMessage("Error: Channel number out of range\n"); 
-    return 0;
-  }
-
-  // Execute command
-  unsigned char wbuf[] = {3<<5 |  Board<<1 | (Channel&16)>>4, Channel<<4 | SetPoint>>8, SetPoint};
-  vector<char> Data = Communicate(wbuf, 3);
-    
-  if (Data.size() == 3) {
-    DAC[Board][Channel] = SetPoint;
-	Volt[Board][Channel] = (double) SetPoint / 0xfff * 90;
+// ***** Set channel voltages *****
+int Crate::SetChannels(map<unsigned int, unsigned int> V) {
+  
+  string Buf;
+
+  if (V.empty()) return 1;
+
+  // Build and execute commands
+  for (map<unsigned int, unsigned int>::const_iterator it = V.begin(); it != V.end(); ++it) {
+	Buf += char(3<<5) |  char(it->first/NUM_CHANNELS<<1 & 0x0f) | char((it->first%NUM_CHANNELS&16)>>4 & 1);
+	Buf += char(it->first%NUM_CHANNELS<<4) | ((it->second>>8) & 0x0f);
+	Buf += char(it->second);
+  }
+  vector<char> Data = Communicate(Buf);
+
+  // Store new voltage values of successful
+  if (Data.size() == Buf.size()) {
+	for (map<unsigned int, unsigned int>::const_iterator it = V.begin(); it != V.end(); ++it) {
+	  DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = it->second;
+	  Volt[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] = 90.0*it->second/0x0fff;
+	}
 	return 1;
   }
-  return Data[0];
-}
-
-
-// ***** Channel set *****
-int Crate::SetAll() {
-  
-  unsigned char wbuf[3*MAX_NUM_BOARDS*NUM_CHANNELS];
-  double Volt = 10;
-  int Count=0;
-  for (int i=0; i<MAX_NUM_BOARDS; i++) for (int j=0; j<NUM_CHANNELS; j++) {
-	wbuf[Count++] = 3<<5 |  i<<1 | (j&16)>>4;
-	wbuf[Count++] = j<<4 | ((int) (Volt/90*0x0fff))>>8;
-	wbuf[Count++] = (int) (Volt/90*0x0fff);
-	Volt += 0.2;
-  }
-  
-  // Execute command
-  vector<char> Data = Communicate(wbuf, 3*MAX_NUM_BOARDS*NUM_CHANNELS);
-    
-  if (Data.size() == 3*MAX_NUM_BOARDS*NUM_CHANNELS) {
-    //DAC[Board][Channel] = SetPoint;
-	//Volt[Board][Channel] = (double) SetPoint / 0xfff * 90;
-	return 1;
-  }
-  return Data[0];
+  return Data[0];  
 }
 
@@ -331,10 +274,9 @@
 bool Crate::Synch() {
   
-  unsigned char wbuf = 0;
   int Trial = 0;
   vector<char> Data;
 
   while(++Trial <= 3) {
-    Data = Communicate(&wbuf, 1);
+    Data = Communicate(string(1, 0));
     if (Data.size() == 3) return true;
     if (Data[0] == 0) break;
Index: /fact/BIASctrl/Crate.h
===================================================================
--- /fact/BIASctrl/Crate.h	(revision 10058)
+++ /fact/BIASctrl/Crate.h	(revision 10059)
@@ -10,4 +10,5 @@
 #include <string>
 #include <vector>
+#include <map>
 
 #include "dis.hxx"
@@ -27,5 +28,5 @@
 	DimService *NameService;
 
-	std::vector<char> Communicate(unsigned char*, int);
+	std::vector<char> Communicate(std::string);
 	void ClearVoltageArrays();
    
@@ -39,4 +40,5 @@
 	int Current[MAX_NUM_BOARDS][NUM_CHANNELS];
 	bool OC[MAX_NUM_BOARDS][NUM_CHANNELS];
+	bool Present[MAX_NUM_BOARDS][NUM_CHANNELS];
 	bool ResetHit;
 	bool WrapOK;
@@ -44,5 +46,5 @@
 	int ErrorCount;
 
-	int DAC[MAX_NUM_BOARDS][NUM_CHANNELS];      // Voltage in DAC units
+	unsigned int DAC[MAX_NUM_BOARDS][NUM_CHANNELS];      // Voltage in DAC units
 	double Volt[MAX_NUM_BOARDS][NUM_CHANNELS];  // Voltage in Volt
 	int CurrentOffset[MAX_NUM_BOARDS][NUM_CHANNELS]; // Offset for current measurement
@@ -50,10 +52,8 @@
 	bool InitOK;
 
-	int SetAll();
+	int SetChannels(std::map<unsigned int, unsigned int>);
 	int ReadAll();
 	int SystemReset();
-	int ReadChannel(unsigned int, unsigned int);
 	int GlobalSet(unsigned int);
-	int ChannelSet(int, int, unsigned int);
 	bool Synch();
 	bool CurrentCalib(double);
Index: /fact/BIASctrl/History.txt
===================================================================
--- /fact/BIASctrl/History.txt	(revision 10058)
+++ /fact/BIASctrl/History.txt	(revision 10059)
@@ -2,3 +2,4 @@
 			program 'hvcontrol' (revision 9852).
 20/8/2010	Removed the possibility to set DAC values.
-17/11/2010	Added possibility for bulk transfers (ReadAll(), SetAll())
+17/11/2010	Added possibility for bulk transfers (ReadAll(), SetChannels())
+24/11/2010	Ramping for many channels possible with bulk transfers
Index: /fact/BIASctrl/User.cc
===================================================================
--- /fact/BIASctrl/User.cc	(revision 10058)
+++ /fact/BIASctrl/User.cc	(revision 10059)
@@ -161,7 +161,8 @@
   double Double;
   struct Range Crt, Chan;
-  
+  vector< map<unsigned int, unsigned int> > Voltages (Crates.size());
+
   // Loop over all parameters
-  for (unsigned int n=1; n < Parameter.size()-1; n++) {
+  for (unsigned int n=1; n < Parameter.size()-1; n+=2) {
 
 	// Extract channel identification
@@ -197,5 +198,5 @@
 	  continue;
 	}
-	
+
 	// Loop over given crates and channels
 	for (int i=Crt.Min; i<=Crt.Max; i++) for (int j=Chan.Min; j<=Chan.Max; j++) {
@@ -211,14 +212,15 @@
 	  else DACValue = (unsigned int) (Double/90*0x0fff);
 
-	  // Set new voltage
-	  if (!RampVoltage(DACValue, i, B, C)) Errors++;
-
+	  Voltages[i][j] = DACValue;
 	} // Channels
   } // Loop over command argument
 
-  // Update DIM service
-  for (unsigned int i=0; i<Crates.size(); i++) Crates[i]->BiasVolt->updateService();
-  
-  if (Errors > 0) PrintMessage("Errors on %d channel(s) occurred\n", Errors);
+  // Ramp voltages and update DIM services
+  for (unsigned int i=0; i<Voltages.size(); i++) {
+	Errors += RampVoltages(i, Voltages[i]);
+    Crates[i]->BiasVolt->updateService();
+  }
+
+  if (Errors > 0) Message(ERROR, "%d errors occurred from SetChannels()", Errors);
 }
 
@@ -232,4 +234,5 @@
   unsigned int DACValue, NBoards = 0;
   FILE *File;
+  map<unsigned int, unsigned int> Voltages;
 
   // Open file
@@ -245,8 +248,11 @@
 	  PrintMessage("Found bias settings for board %s (#%d)\n\r", Crates[Crate]->Name, Crate);
 
+	  Voltages.clear();
 	  Board = 0;  Channel = 0;
 	  while (fscanf(File, "%u", &DACValue)==1 && Board<MAX_NUM_BOARDS) {
+		Voltages[Board*NUM_CHANNELS+Channel] = DACValue;
+
 	    // Ramp channel to new voltage
-    	if (!RampVoltage(DACValue, Crate, Board, Channel)) {
+    	/*if (!RampVoltage(DACValue, Crate, Board, Channel)) {
 	      Errors++;
 	      PrintMessage("Error: Could not ramp board %d, channel %d\n", Board, Channel);
@@ -255,5 +261,5 @@
 	      PrintMessage("Ramped board %d, channel %d to %u (%.2f V)                         \r",
 	    	 Board, Channel, DACValue, (double) DACValue/0x0fff*90);
-		}
+		}*/
 
 		if(++Channel == NUM_CHANNELS) {
@@ -262,4 +268,7 @@
 		}
 	  }
+
+	  // Ramp channels
+	  Errors += RampVoltages(Crate, Voltages);
 
       // Update DIM service
@@ -278,5 +287,5 @@
   else if (Errors == 0) PrintMessage("Success: Read bias settings for all connected crates\n");
 
-  if (Errors != 0) PrintMessage("Warning: Errors on %d channel(s) occurred\n", Errors);
+  if (Errors != 0) PrintMessage("Warning: %d error(s) occurred\n", Errors);
 
   if (fclose(File) != 0) PrintMessage("Error: Could not close file '%s'\n", Parameter[1].c_str());
@@ -409,5 +418,6 @@
     for (int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
 	  if (j%12 == 0) PrintMessage("\n%3.1d:  ", j);
-      if (Parameter.size() == 1) PrintMessage("%#5.2f ",Crates[i]->Volt[j/NUM_CHANNELS][j%NUM_CHANNELS]);
+	  if (!Crates[i]->Present[j/NUM_CHANNELS][j%NUM_CHANNELS]) PrintMessage("  -   ");
+      else if (Parameter.size() == 1) PrintMessage("%#5.2f ",Crates[i]->Volt[j/NUM_CHANNELS][j%NUM_CHANNELS]);
 	  else if (Match(Parameter[1], "dac")) PrintMessage("%5d ", Crates[i]->DAC[j/NUM_CHANNELS][j%NUM_CHANNELS]);
 	  else PrintMessage("%#5.2f %s ", (Crates[i]->Current[j/NUM_CHANNELS][j%NUM_CHANNELS]-Crates[i]->CurrentOffset[j/NUM_CHANNELS][j%NUM_CHANNELS])*1.2, Crates[i]->OC[j/NUM_CHANNELS][j%NUM_CHANNELS] ? "OC":"");
@@ -474,17 +484,30 @@
 // Ramp to new voltage with maximum step size given in fMaxDiff
 // No ramping when decreasing voltage
-bool User::RampVoltage(unsigned int Target, int Crate, int Board, int Channel) {
-
-  while (Crates[Crate]->DAC[Board][Channel] != (int) Target) {	  
-    int Diff = Target - Crates[Crate]->DAC[Board][Channel];
-    if (Diff > (int) fMaxDiff) Diff = fMaxDiff;
-
-    if (Crates[Crate]->ChannelSet(Board, Channel, Crates[Crate]->DAC[Board][Channel]+Diff) != 1) {
-      Message(ERROR, "Could not set bias of crate %d, board %d, channel %d. Skipping channel\n", Crate, Board, Channel);
-      return false;
-    }
-  }
-
-  return true;
+unsigned int User::RampVoltages(int Crate, map<unsigned int, unsigned int> Voltages) {
+
+  map<unsigned int, unsigned int> Target;
+  unsigned int Errors = 0;
+
+  // Ramp until all channels at desired value
+  while (!Voltages.empty()) {
+    // Remove channels already at target
+	for (map<unsigned int, unsigned int>::iterator it = Voltages.begin(); it != Voltages.end(); ++it) {
+	  if (Crates[Crate]->DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] == it->second) Voltages.erase(it);
+	}
+	
+	// Limit voltage changes to fMaxDiff
+	Target = Voltages;
+	for (map<unsigned int, unsigned int>::iterator it = Target.begin(); it != Target.end(); ++it) {
+	  if (Crates[Crate]->DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] + fMaxDiff/2 < it->second) {
+		it->second = Crates[Crate]->DAC[it->first/NUM_CHANNELS][it->first%NUM_CHANNELS] + fMaxDiff/2;
+	  }
+	}	
+	
+	// Set channels to next target and wait 10 ms
+	if (Crates[Crate]->SetChannels(Target) != 1) Errors++;
+	usleep(10000);
+  }
+  
+  return Errors;
 }
 
@@ -522,11 +545,17 @@
       }
 
+	  map<unsigned int, unsigned int> Voltages;
+	  
       for (int j=0; j<MAX_NUM_BOARDS*NUM_CHANNELS; j++) {
     	if (Crates[i]->OC[j/NUM_CHANNELS][j%NUM_CHANNELS]) {
 		  Message(WARN, "Overcurrent on crate %d, board %d, channel %d, setting voltage to zero", i, j/NUM_CHANNELS, j%NUM_CHANNELS);
-		  Crates[i]->ChannelSet(j/NUM_CHANNELS, j%NUM_CHANNELS, 0);
-		  Crates[i]->SystemReset();
+		  Voltages[j] = 0;
+		  //Crates[i]->ChannelSet(j/NUM_CHANNELS, j%NUM_CHANNELS, 0);
     	}
       }
+	  if (!Voltages.empty()) {
+		Crates[i]->SetChannels(Voltages);
+		Crates[i]->SystemReset();
+	  }
 	} // for
 
Index: /fact/BIASctrl/User.h
===================================================================
--- /fact/BIASctrl/User.h	(revision 10058)
+++ /fact/BIASctrl/User.h	(revision 10059)
@@ -54,5 +54,5 @@
 
 	void PrintMessage(const char *, ...);
-	bool RampVoltage(unsigned int, int, int, int);
+	unsigned int RampVoltages(int, std::map<unsigned int, unsigned int>);
 	void Monitor();
 	static void LaunchMonitor(User *);
