/***************************************************************************** - - - POLONY SEQUENCER ACQUISITION SUITE - - Church Lab - - Harvard Medical School - - - - Free software for running a Polony Sequencing automated microscope - - - - ========================================================================= - - - - - - autofocus.cpp - - - - Program to autofocus brightfield or fluorescence images of Polony beads - - - - Written by Michelle Kuykendal, 10-10-2005 - - - - Revised - - - - - - This software may be used, modified, and distributed freely, but this - - header may not be modified and must appear at the top of this file. - - - - - *****************************************************************************/ /****************************************************************************** ******************************************************************************* **** File: cfilter.cpp **** **** Requirements: cfilter.h and cport.h should exist in the same **** **** directory as this file. if the file is being used in the GUI_Devices **** **** project, the StdAfx.h and StdAfx.cpp files should also exit in the **** **** same directory. if this file is used outside of the GUI_Devices **** **** project(or any Microsoft Visual project) then the line of code **** **** "#include "StdAfx.h" may be commented. **** **** Purpose: this file defines the functions of the CFilter class to **** **** be used with a Sutter Instruments Lambda 10-3 filter wheel. it **** **** enables the user to set the position and speed of filter wheels A **** **** and C, get the position and speed of filter wheels A and C, open **** **** shutter A, close shutter A, initialize the filter wheel, and close **** **** the filter wheel. it also provides functions to write to and read **** **** from the filter wheel via the comm port to enable the addition of **** **** new functions in the future. **** **** Initial Version: Aug. 10, 2005 **** **** Programmer: Michelle Kuykendal **** ******************************************************************************* ******************************************************************************/ /*FILTER CONFIGURATION: 0 Cy3 1 Cy5 2 OPEN 3 --- 4 --- 5 3Cy5 6 3Cy3 7 3FITC 8 FITC 9 TxRed */ #include "StdAfx.h" //header file for microsoft visual functionality #include "cfilter.h" //definition of the filter class #include "cport.h" //serial port class #include //used for retrieving system clock time #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif //REQUIREMENTS: none. //USE: CFilter() is the constructor for the filter class. it will // initialize the variable filterIsInit (used to check for filter // intialization) to false, and will initialize WheelSettings (after a // call to GetPosition(), this char * variable will hold the speed, // position of wheel A and position of wheel C if the return is true. // it will hold the string, "Could not get the filter wheel settings" // if the return is false) variables to NULL. it will intialize the // min and max variables for speed, position of wheel A and position // of wheel C. //RETURN VALUE: none. CFilter::CFilter(Reporter* rep) { r = rep; filterIsInit = false;//variable used to check if the filter is initialized //initialize variable array to hold the current speed, posA and posC for(int temp = 0; temp < 40; temp++) WheelSettings[temp] = NULL; speedmin = 0;//minimum speed position allowed speedmax = 7;//maximum speed position allowed posAmin = 0;//minimum A position allowed posAmax = 9;//maximum A position allowed posCmin = 0;//minimum C position allowed posCmax = 9;//maximum C position allowed //when looping to check for read variables, tTimeOut is the maximum wait // time allowed. it is determined by reading the system clock time. tTimeOut = 10000;//in milliseconds } //REQUIREMENTS: none. //USE: ~CFilter() is the destructor for the filter class. //RETURN VALUE: none. CFilter::~CFilter() { } //REQUIREMENTS: a call to Init() should be made prior to this call for // proper execution, however, a failure will not occur otherwise. //USE: OpenShutterA() will first check that the filter wheel is // initialized and then send the command code 170 to the filter wheel. // it will wait for a carriage return to be read to confirm the opening // of the shutter. //RETURN VALUE: the return will be false if the filter was not previously // initialized, or if the WriteFilter() or ReadFilter() call is // unsuccessful. otherwise, the return will be true when the filter wheel // opens shutter A. bool CFilter::OpenShutterA(){ unsigned char Writer;//variable to hold byte to be written Checker = 13;//set the read checker to carriage return //write to Filter "Open Shutter A", code 170 Writer = 170; if(WriteFilter(Writer)){ if(!ReadFilter(1)){//read until carriage return return false; } } else{//the write was unsuccessful r->error("write unsuccessful to open shutter", 0); return false; } return true;//everything was successful } bool CFilter::CloseShutterA(){ unsigned char Writer; Checker = 13;//set the read checker to carriage return //write to Filter "Close Shutter A", code 172 Writer = 172; if(WriteFilter(Writer)){ if(!ReadFilter(1)){//read until carriage return return false; } } else{//the write was unsuccessful r->error("write unsuccessful to close shutter", 0); return false; } return true;//everything was successful } //BLOCKS UNTIL WHEELS ARE IN POSITION bool CFilter::SetPosition(int speed, int numfilterA, int numfilterC){ //wheel status bytes contain 3 types of info: desired filter wheel, // speed, and position organized as follows: b7b6b5b4b3b2b1b0. b7 is // the desired filter wheel: 0 for wheel A or C and 1 for wheel B. // this bit should always be 0. b6b5b4 contains the wheel speed // (0 - 7), and the lower nibble, b3b2b1b0 contains the wheel // position (0-9). anything above 9 in the lower nibble is an invalid // position. unsigned char setspeed = 0x00; unsigned char statusA;//will hold value to write to wheel A unsigned char statusC;//will hold value to write to wheel C //check the user passed speed (0-7) and assign it to setspeed variable // if invalid speed is passed, default the speed to 2 switch(speed) { case 0: setspeed = setspeed | 0x00; break; case 1: setspeed = setspeed | 0x10; break; case 2: setspeed = setspeed | 0x20; break; case 3: setspeed = setspeed | 0x30; break; case 4: setspeed = setspeed | 0x40; break; case 5: setspeed = setspeed | 0x50; break; case 6: setspeed = setspeed | 0x60; break; case 7: setspeed = setspeed | 0x70; break; default:setspeed = setspeed | 0x20; break; } //assign setspeed value to both wheel A and C status variables statusA = setspeed; statusC = setspeed; //check the user passed position for wheel A and OR it into the status switch(numfilterA) { case 0: statusA = statusA | 0x00; break; case 1: statusA = statusA | 0x01; break; case 2: statusA = statusA | 0x02; break; case 3: statusA = statusA | 0x03; break; case 4: statusA = statusA | 0x04; break; case 5: statusA = statusA | 0x05; break; case 6: statusA = statusA | 0x06; break; case 7: statusA = statusA | 0x07; break; case 8: statusA = statusA | 0x08; break; case 9: statusA = statusA | 0x09; break; default:statusA = statusA | 0x00; break; } //check the user passed position for wheel C and OR it into the status switch(numfilterC) { case 0: statusC = statusC | 0x00; break; case 1: statusC = statusC | 0x01; break; case 2: statusC = statusC | 0x02; break; case 3: statusC = statusC | 0x03; break; case 4: statusC = statusC | 0x04; break; case 5: statusC = statusC | 0x05; break; case 6: statusC = statusC | 0x06; break; case 7: statusC = statusC | 0x07; break; case 8: statusC = statusC | 0x08; break; case 9: statusC = statusC | 0x09; break; default:statusC = statusC | 0x00; break; } unsigned char Writer;//variable to hold byte to be written Checker = 13;//set the read checker to carriage return //write status to wheel C to include user defined speed and position Writer = 252;//code 252 tells the filter that wheel C will be assigned if(!WriteFilter(Writer)){ r->error("write code 252 to wheel failed", 0); return false; } Writer = statusC; if(!WriteFilter(Writer)){ r->error("write statusC to wheel failed", 0); return false; } //write status to wheel A to include user defined speed and position Writer = statusA; if(!WriteFilter(Writer)){ r->error("write statusA to wheel failed", 0); return false; } //check for two carriage returns to confirm both status A and C are set if(!ReadFilter(2)){ r->error("at least one of the two wheels is not set", 0); return false; } return true;//everything was successful } //REQUIREMENTS: a call to Init() should be made prior to this call for // proper execution, however, a failure will not occur otherwise. //USE: GetWheel() will first check that the filter wheel is initialized // and then will send the filter device a status command, code 204. // the function will parse through the returned string of bytes to retrieve // the status of wheel A and wheel C, which will contain the speed and // position of the specified wheel. //RETURN VALUE: if the call is successful the return will be a string // containing the current filter parameters in the format, "PosA,PosC,Speed // = currentPositionA, currentPositionC,currentSpeed". the string will // contain "Could not get the filter wheel settings" if the filter was not // previously initialized, or if the WriteFilter() or ReadFilter() call // is unsuccessful. char *CFilter::GetPosition() { if(filterIsInit)//check to see if the filter has been initialized { sprintf(WheelSettings, "Could not get the filter wheel settings"); int posA;//will hold the wheel A position int posC;//will hold the wheel C position int spd; //will hold the speed of both wheels unsigned char statusA;//for saving retrieved status A code unsigned char statusC;//for saving retrieved status C code unsigned char Writer;//variable to hold byte to be written Writer = 204;//"Status" command code if(!WriteFilter(Writer)) return WheelSettings; Checker = 204;//set the read checker to the status code if(!ReadFilter(1))//read until status code return WheelSettings; if(!ReadFilter(0))//read one byte: filter wheel A status return WheelSettings; statusA = PortFilter.mInOne;//save the wheel A status if(!ReadFilter(0))//read one byte: filter wheel B status, ignore return WheelSettings; Checker = 252;//set the read checker to the wheel C designating code if(!ReadFilter(1))//read until wheel C designating code return WheelSettings; if(!ReadFilter(0))//read one byte: filter wheel C status return WheelSettings; statusC = PortFilter.mInOne;//save the wheel C status Checker = 13;//set the read checker to carriage return if(!ReadFilter(1))//read until carriage return return WheelSettings; //status bytes contains 3 types of info: desired filter wheel, speed, // and position organized as follows: b7b6b5b4b3b2b1b0. b7 is the // desired filter wheel: 0 for wheel A or C and 1 for wheel B. this // bit should always be 0. b6b5b4 contains the wheel speed (0 - 7), // and the lower nibble, b3b2b1b0 contains the wheel position (0-9). // anything above 9 in the lower nibble is an invalid position. //ANDing off the upper nibble to isolate position info posA = statusA & 0x0F; posC = statusC & 0x0F; //ANDing off the lower nibble to isolate speed info and shifting // the bits right four to get the correct number. spd = (statusA & 0xF0)>>4; //compose a private variable string formatted as "posA,posC,spd" sprintf(WheelSettings, "PosA,PosC,Speed = %i,%i,%i", posA, posC, spd); } else sprintf(WheelSettings, "Could not get the filter wheel parameters"); return WheelSettings; } //REQUIREMENTS: the stage device should be connected to comm port 9 //USE: Init() will first check to be sure the filter has not already been // initialized. it will then create and open comm port 9 for communication // with the filter wheel. it will initialize the device to go online, // which allows the receipt of codes from the remote computer station. it // will reset the device (set all parameters to defaults) and it will set // the filter to fast-mode shutter (assigned to shutter A) for faster // movement operation. finally, the get controller type and config command // will be issued and returns a 29 bytes string containing device // information, although the string is not currently saved. all commands // wait for a carriage return to be read to confirm execution of code. //RETURN VALUE: the return will be false is the filter was already // initialized or if any of the writes and reads failed. the return will // be true if the filter was not already initialized, the comm port was // opened successfully, and the initialization commands were properly // sent and executed. bool CFilter::Init() { if(!filterIsInit)//only initialize filter if it's not already initalized { filterIsInit = true;//set the initialization checker to true sprintf(PortFilter.mPort, "COM9");//COM9 will be opened if(PortFilter.OpenCPort())//open and setup the comm port { unsigned char Writer;//variable to hold byte to be written Checker = 13;//set the read checker to carriage return //write to Filter "Transfer to OnLine", code 238 Writer = 238; if(WriteFilter(Writer)) { if(!ReadFilter(1))//read until carriage return received { Close();//close the comm port return false;//the read was unsuccessful } } else//the write was unsuccessful { Close();//close the comm port return false; } //write to Filter "Reset", code 251 Writer = 251; if(WriteFilter(Writer)) { if(!ReadFilter(1))//read until carriage return received { Close();//close the comm port return false;//the read was unsuccessful } } else//the write was unsuccessful { Close();//close the comm port return false; } //write to Filter "Fast-mode Shutter", code 220 followed by 1 Writer = 220;//fast-mode if(!WriteFilter(Writer)) { Close();//close the comm port return false;//the write was unsuccessful } Writer = 1;//shutter A if(WriteFilter(Writer)) { if(!ReadFilter(1))//read until carriage return received { Close();//close the comm port return false;//the read was unsuccessful } } else//the write was unsuccessful { Close();//close the comm port return false; } //write to Filter "Get Controller Type and Config", code 253 Writer = 253; if(WriteFilter(Writer)) { if(!ReadFilter(1))//read until carriage return received { Close();//close the comm port return false;//the read was unsuccessful } } else//the write was unsuccessful { Close();//close the comm port return false; } return true;//everything was successful } else//the port could not be properly opened { Close();//close the comm port return false; } } else//the filter was already initialized return false; } //REQUIREMENTS: a call to Init() should be made prior to this call for // proper execution, however, a failure will not occur otherwise. //USE: Close() will check to see that the filter was first intialized. it // will then close the comm port that was opened during the call to Init(), // and reset the filter initialization checker to false. //RETURN VALUE: if the port was successfully closed, the return will be // true. otherwise,the return will be false. bool CFilter::Close() { if(filterIsInit)//only close the port if it was previously initialized { if(PortFilter.CloseCPort())//close the comm port { filterIsInit = false;//reset the init checker to false return true; } else return false;//the comm port could not be closed } else//the stage was not first initialized return false; } //REQUIREMENTS: a call to Init() should be made prior to this call for // proper execution, however, a failure will not occur otherwise. //USE: WriteFilter() will check that the filter was first intialized. // it will then write the passed byte to the comm port that was opened // during the call to Init(). while the write has not completed (known // because mResWrite, the result of the write, will be false) the function // will continuously check for completion. NOTE: the WriteCPortOneByte() // command will only return false if an error occurs. the return value of // the function should not be used to determine if the write was completed. // the return value should only be used to confirm that an error did or did // not occur. if the write command was executed, but the write was not // immediately completed, it will return false and the mResWrite variable // will remain false. if the write was immediately completed, the mResWrite // variable will be true. //RETURN VALUE: the return will be false if the stage has not been first // initialized or the WriteCPortOneByte() call returned false due to an // error. the return will be true if the filter is already intialized and // the write is successful. bool CFilter::WriteFilter(unsigned char ToWrite) { if(filterIsInit)//check to see if the filter has been initialized { //set the output byte to the user passed byte PortFilter.mOutOne = ToWrite; if(PortFilter.WriteCPortOneByte())//write the output byte to the port { while(PortFilter.mResWrite!=true)//the write has not completed PortFilter.CheckWrite();//check for completion } else//an error occurred during the write return false; return true; } else//the filter was not first initialized return false; } //REQUIREMENTS: a call to Init() should be made prior to this call for // proper execution, however, a failure will not occur otherwise. the // checker variable should first be set to the character that is expected // to be read from the filter. if it is not first set, the function will // return false. //USE: ReadFilter() will check to see that the filter was first intialized. // it will then read one byte from the comm port opened during the call to // Init(). while the read has not completed (known because mResRead, the // result of the read, will be false) the function will continuously check // for completion. if Checker is assigned and NumChecker is greater than // zero, the function will read until the number of bytes specified by // NumChecker that match the Checker byte has been retrieved. if NumChecker // is zero, the function will read in one byte and will not confirm its // value. in this case, it does not matter what Checker is assigned to. // if NumChecker is greater than zero, however, the calling function should // be sure to set the Checker variable to one that is expected. generally, // the filter wheel will always return a carriage return at the end of a // command execution, which, when the Checker variable is set to 13 (the // ascii code for a carriage return) can be used to confirm a command // completion. NOTE: the ReadCPortOneByte() command will only return false // if an error occurs. the return value of the function should // not be used to determine if the read was completed. the return value // should only be used to confirm that an error did or did not occur. if // the read command was executed, but the read was not immediately // completed, it will return false and the mResRead variable will remain // false. if the read was immediately completed, the mResRead variable // will be true. //RETURN VALUE: the return will be false if the filter has not been first // initialized or the ReadCPortOneByte() call returned false due to an // error. the return will be true if the filter is already intialized and // if the read is successful. bool CFilter::ReadFilter(int NumChecker) { if(filterIsInit)//check to see if the filter has been initialized { do//to be sure that a read is always executed at least once { if(PortFilter.ReadCPortOneByte())//issue the comm port read command { while(PortFilter.mResRead != true)//if the read is not complete PortFilter.CheckRead();//check for read completion } else//an error occurred during the read call return false; //if the read byte is equal to the assigned Checker byte, decrement // the counter for number of bytes to be read that are equal to // Checker if(PortFilter.mInOne == Checker) NumChecker--; //loop to continue reading if not all bytes are read }while(NumChecker > 0); //the read was successful and the correct number of checker bytes // was read return true; } else//the filter was not first initialized return false; }