/* * 1 = open * 0 = close */ int ASIFW1000Hub::GetShutterPosition(MM::Device& device, MM::Core& core, int shutterNr, bool& pos) { //ClearAllRcvBuf(device, core); ostringstream os; os << "SQ " << shutterNr; int ret = ExecuteCommand(device, core, os.str().c_str()); // analyze answer ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; string response = rcvBuf_; // If the answer is too short, there is likely no shutter card (we could do a better check) if (response.length() < 2) { return ERR_SHUTTER_NOT_FOUND; } int x = atoi(response.substr(response.length() - 2).c_str()); // sometimes, the controller does not answer, but sends 0. ask once more if (x < 16) { ret = ExecuteCommand(device, core, os.str().c_str()); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); response = rcvBuf_; x = atoi(response.substr(response.length() - 2).c_str()); } if (shutterNr==1) x = x >> 1; pos = x & 1; return DEVICE_OK; }
int ASIFW1000Hub::SetFilterWheelPosition(MM::Device& device, MM::Core& core, int wheelNr, int pos) { if (wheelNr != activeWheel_) // TODO: error checking SetCurrentWheel(device, core, wheelNr); const char* command = "MP "; ostringstream os; os << command << pos; // send command int ret = ExecuteCommand(device, core, os.str().c_str()); if (ret != DEVICE_OK) return ret; // devices echos command and returns position ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; int posread = rcvBuf_[strlen(rcvBuf_)-1] - '0'; if ( pos != posread) return ERR_SETTING_WHEEL; return DEVICE_OK; }
// Gets the current wheels from the controller // Also sets private variable activeWheel_ int ASIFW1000Hub::GetCurrentWheel(MM::Device& device, MM::Core& core, int& wheelNr) { const char* command = "FW"; // send command int ret = ExecuteCommand(device, core, command); if (ret != DEVICE_OK) return ret; // make sure there were no errors: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; wheelNr = rcvBuf_[strlen(rcvBuf_)-1] - '0'; if ( (wheelNr == 0) || (wheelNr == 1) ) { activeWheel_ = wheelNr; return DEVICE_OK; } else { return ERR_UNEXPECTED_ANSWER; } }
int ASIFW1000Hub::SetCurrentWheel(MM::Device& device, MM::Core& core, int wheelNr) { const char* command = "FW "; ostringstream os; os << command << wheelNr; // send command int ret = ExecuteCommand(device, core, os.str().c_str()); if (ret != DEVICE_OK) return ret; // make sure there were no errors: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; int x = rcvBuf_[strlen(rcvBuf_)-1] - '0'; if (x == wheelNr) { activeWheel_ = wheelNr; return DEVICE_OK; } else { return ERR_SETTING_WHEEL; } }
int ASIFW1000Hub::GetVersion(MM::Device& device, MM::Core& core, char* version) { int ret = ExecuteCommand(device, core, "VN "); if (ret != DEVICE_OK) return ret; ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; // get substring containing version number. Offset is caused by echoing of the command given int i=3; do { i++; version[i-4]=rcvBuf_[i]; } while (rcvBuf_[i]); version[i-3] = '\0'; // terminate the string // Don't know why, but we need a little break after asking for version number: #ifdef WIN32 Sleep(100); #else usleep(100000); #endif if (strlen(rcvBuf_) < 3) { return ERR_NOT_CONNECTED; } return DEVICE_OK; }
/* * The Spectral LMM5 has a silly difference between USB and serial communication: * Commands can be sent straight to USB. Commands to the serial port need to converted in some kind of weird ASCI: The command "0x1A0xFF0x000x12<CR>" becomes "1AFF0012<CR>". Presumably, the same weird conversion takes place on the way back. We handle this translation in this function */ int SpectralLMM5Interface::ExecuteCommand(MM::Device& device, MM::Core& core, unsigned char* buf, unsigned long bufLen, unsigned char* answer, unsigned long answerLen, unsigned long& read) { int ret; if (portType_ == MM::SerialPort) { std::string serialCommand; char tmp[3]; tmp[2] = 0; for (unsigned long i=0; i<bufLen; i++) { sprintf(tmp, "%.2x", buf[i]); serialCommand += tmp; } ret = core.SetSerialCommand(&device, port_.c_str(), serialCommand.c_str(), "\r"); } else // check for USB port { ret = core.WriteToSerial(&device, port_.c_str(), buf, bufLen); } if (ret != DEVICE_OK) return ret; if (portType_ == MM::SerialPort) { char strAnswer[128]; read = 0; ret = core.GetSerialAnswer(&device, port_.c_str(), 128, strAnswer, "\r"); if (ret != DEVICE_OK) return ret; std::ostringstream os; os << "LMM5 answered: " << strAnswer << " Port status: " << ret; core.LogMessage(&device, os.str().c_str(), true); // 'translate' back into numbers: std::string tmp = strAnswer; for (unsigned int i=0; i < tmp.length()/2; i++) { char * end; long j = strtol(tmp.substr(i*2,2).c_str(), &end, 16); answer[i] = (unsigned char) j; read++; } } else if (portType_ == MM::HIDPort) { // The USB port will attempt to read up to answerLen characters ret = core.ReadFromSerial(&device, port_.c_str(), answer, answerLen, read); if (ret != DEVICE_OK) return ret; /* // Uncomment for debugging (although port should give the same info) std::ostringstream os; os << "LMM5 answered: " << std::hex << std::setfill('0'); for (unsigned int i=0; i < read; i++) os << std::setw(2) << (unsigned int) answer[i] << " "; core.LogMessage(&device, os.str().c_str(), true); */ } return DEVICE_OK; }
/* * The Spectral LMM5 has a silly difference between USB and serial communication: * Commands can be sent straight to USB. Commands to the serial port need to converted in some kind of weird ASCI: The command "0x1A0xFF0x000x12<CR>" becomes "1AFF0012<CR>". Presumably, the same weird conversion takes place on the way back. We handle this translation in this function */ int SpectralLMM5Interface::ExecuteCommand(MM::Device& device, MM::Core& core, unsigned char* buf, unsigned long bufLen, unsigned char* answer, unsigned long answerLen, unsigned long& read) { int ret; if (portType_ == MM::SerialPort) { std::string serialCommand; char tmp[3]; tmp[2] = 0; for (unsigned long i=0; i<bufLen; i++) { sprintf(tmp, "%.2x", buf[i]); serialCommand += tmp; } ret = core.SetSerialCommand(&device, port_.c_str(), serialCommand.c_str(), "\r"); } else // check for USB port { unsigned char c[2]; c[0]=0x01; c[1]=0x02; ret = core.WriteToSerial(&device, port_.c_str(), c, 2); //ret = core.WriteToSerial(&device, port_.c_str(), buf, bufLen); } if (ret != DEVICE_OK) return ret; if (portType_ == MM::SerialPort) { char strAnswer[128]; read = 0; ret = core.GetSerialAnswer(&device, port_.c_str(), 128, strAnswer, "\r"); if (ret != DEVICE_OK) return ret; std::ostringstream os; os << "LMM5 answered: " << strAnswer << " Port status: " << ret; core.LogMessage(&device, os.str().c_str(), true); // 'translate' back into numbers: std::string tmp = strAnswer; for (unsigned int i=0; i < tmp.length()/2; i++) { char * end; long j = strtol(tmp.substr(i*2,2).c_str(), &end, 16); answer[i] = (unsigned char) j; // printf("c:%x i:%u j:%ld\n", answer[i], i, j); read++; } } else // TODO: check that we have a USB port { // The USB port will attempt to read up to answerLen characters ret = core.ReadFromSerial(&device, port_.c_str(), answer, answerLen, read); if (ret != DEVICE_OK) return ret; std::ostringstream os; os << "LMM5 answered: "; for (unsigned int i=0; i < read; i++) os << std::hex << answer[i]; os << std::endl; core.LogMessage(&device, os.str().c_str(), true); } return DEVICE_OK; }
/* * An 'A' acknowledges receipt of a command, ('N' means it is not understood) * Function is not really appropriately named */ int CSUXHub::GetAcknowledgment(MM::Device& device, MM::Core& core) { // block until we get a response int ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; return Acknowledge(); }
/* * Queries CSU for current NIR Shutter */ int CSUW1Hub::GetNIRShutterPosition(MM::Device& device, MM::Core& core, bool& open) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "SH2, ?"); // analyze what comes back: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; open = (strstr(rcvBuf_, "OPEN") != 0); return DEVICE_OK; }
int CARVIIHub::GetPrismSliderPosition(MM::Device& device, MM::Core& core, int pos) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rP"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; // CARVII echoes command, motor state is in bit 3 pos = rcvBuf_[2]; return DEVICE_OK; }
int CARVIIHub::GetShutterPosition(MM::Device& device, MM::Core& core, int pos) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rS"); // analyze what comes back: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; //CARVII echoes command, shutter position is in bit 3 pos = rcvBuf_[2]; return DEVICE_OK; }
int CARVIIHub::GetTouchScreenState(MM::Device& device, MM::Core& core, int state) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rM"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; // CARVII echoes command, motor state is in bit 3 state = rcvBuf_[2]; return DEVICE_OK; }
/* * TODO: improve error reporting */ int CSU22Hub::GetDriveSpeedPosition(MM::Device& device, MM::Core& core, int& pos) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rsm"); // analyze what comes back: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; int speed = atoi(rcvBuf_); pos = speed; return DEVICE_OK; }
/* * An 'A' acknowledges receipt of a command, ('N' means it is not understood) * Function is not really appropriately named */ int CSU22Hub::GetAcknowledgment(MM::Device& device, MM::Core& core) { // block until we get a response int ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; if (rcvBuf_[1]=='N') return 1; if (rcvBuf_[1]!='A') return DEVICE_SERIAL_INVALID_RESPONSE; return DEVICE_OK; }
int ASIFW1000Hub::CloseShutter(MM::Device& device, MM::Core& core, int shutterNr) { ostringstream os; os << "SC " << shutterNr; int ret = ExecuteCommand(device, core, os.str().c_str()); if (ret != DEVICE_OK) return ret; // Shutter will answer '0', we need to read this out or there will be trouble down the line: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; return DEVICE_OK; }
int CSUXHub::GetDichroicPosition(MM::Device& device, MM::Core& core, long &dichroic) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "DM_POS, ?"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; ret = Acknowledge(); if (ret != DEVICE_OK) return ret; dichroic = atol(rcvBuf_); return DEVICE_OK; }
/* * 1 = closed * 0 = open */ int CSU22Hub::GetShutterPosition(MM::Device& device, MM::Core& core, int& pos) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rsn"); // analyze what comes back: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; int x = rcvBuf_[2]; x = x -'0'; x = x & 2; (x == 2) ? (pos = 1) : (pos = 0); return DEVICE_OK; }
/* * 1 = closed * 0 = open */ int CSUXHub::GetShutterPosition(MM::Device& device, MM::Core& core, int& pos) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "SH, ?"); // analyze what comes back: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; if (strstr(rcvBuf_, "CLOSE") != 0) pos = 1; pos = 0; return DEVICE_OK; }
int CSU22Hub::GetNDFilterPosition(MM::Device& device, MM::Core& core, int& pos) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rsn"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; int x = rcvBuf_[2]; // ND status info is in bit 3 x = x -'0'; x = x & 4; (x==4) ? (pos = 1) : (pos = 0); return DEVICE_OK; }
/* * Reports the maximum drive speed available from this model */ int CSUXHub::GetMaxDriveSpeed(MM::Device& device, MM::Core& core, long& maxSpeed) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "MS_MAX, ?"); // analyze what comes back: ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; ret = Acknowledge(); if (ret != DEVICE_OK) return ret; maxSpeed = atol(rcvBuf_); return DEVICE_OK; }
/* * Gets speed of filter wheel (0-3) */ int CSUXHub::GetFilterWheelSpeed(MM::Device& device, MM::Core& core, long wheelNr, long& speed) { ClearAllRcvBuf(device, core); ostringstream os; os << "FW_SPEED, " << wheelNr << ", ?"; int ret = ExecuteCommand(device, core, os.str().c_str()); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; ret = Acknowledge(); if (ret != DEVICE_OK) return ret; speed = atol(rcvBuf_); return DEVICE_OK; }
int ASIFW1000Hub::GetFilterWheelPosition(MM::Device& device, MM::Core& core, int wheelNr, int& pos) { if (wheelNr != activeWheel_) SetCurrentWheel(device, core, wheelNr); //ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "MP"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; // TODO: error checking pos = rcvBuf_[strlen(rcvBuf_)-1] - '0'; return DEVICE_OK; }
int CARVIIHub::GetIntensityIrisPosition(MM::Device& device, MM::Core& core, int pos) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rV"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; // CARVII echoes command, iris position is in bits 3-6 pos = rcvBuf_[3]*100 + rcvBuf_[4]*10 + rcvBuf_[5]; // bit 3 is blank for positions <1000, equals 1 for 1000 and above if (rcvBuf_[2] == 1) pos += 1000; return DEVICE_OK; }
/* * The LMM5 USB HID commands are a sequence of binary bytes with no terminator. * The serial commands are the same bytes formatted as an ASCII hex string, two * characters per byte, and terminated with a CR; e.g.: * USB: "\x1a\xff\x00\x12" (4 bytes) * RS-232: "1AFF0012\r" (9 bytes) * The opposite transformation takes place for the reply. * * This function abstracts these differences. Note that the exact answerLen is * important for USB HID: reading excess bytes can result in garbage being * appended to the reply (at least on Windows). */ int SpectralLMM5Interface::ExecuteCommand(MM::Device& device, MM::Core& core, unsigned char* buf, unsigned long bufLen, unsigned char* answer, unsigned long answerLen, unsigned long& read) { int ret; if (portType_ == MM::SerialPort) { std::string serialCommand; char tmp[3]; tmp[2] = 0; for (unsigned long i=0; i<bufLen; i++) { sprintf(tmp, "%.2x", buf[i]); serialCommand += tmp; } ret = core.SetSerialCommand(&device, port_.c_str(), serialCommand.c_str(), "\r"); } else // check for USB port { ret = core.WriteToSerial(&device, port_.c_str(), buf, bufLen); } if (ret != DEVICE_OK) return ret; if (portType_ == MM::SerialPort) { char strAnswer[128]; read = 0; ret = core.GetSerialAnswer(&device, port_.c_str(), 128, strAnswer, "\r"); if (ret != DEVICE_OK) return ret; // 'translate' back into numbers: std::string tmp = strAnswer; for (unsigned int i=0; i < tmp.length()/2; i++) { char * end; long j = strtol(tmp.substr(i*2,2).c_str(), &end, 16); answer[i] = (unsigned char) j; read++; } } else if (portType_ == MM::HIDPort) { // The USB port will attempt to read up to answerLen characters ret = core.ReadFromSerial(&device, port_.c_str(), answer, answerLen, read); if (ret != DEVICE_OK) return ret; } return DEVICE_OK; }
int ASIFW1000Hub::SetVerboseMode(MM::Device& device, MM::Core& core, int level) { ostringstream os; os << "VB " << level; int ret = ExecuteCommand(device, core, os.str().c_str()); if (ret != DEVICE_OK) return ret; ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; int levelRead = rcvBuf_[strlen(rcvBuf_)-1] - '0'; if ( level != levelRead) return ERR_SETTING_VERBOSE_LEVEL; return DEVICE_OK; }
/* * Queries CSU for current Magnifier position * 0 = Position 1 * 1 = Position 2 */ int CSUW1Hub::GetMagnifierPosition(MM::Device& device, MM::Core& core, int nr, int& pos) { ClearAllRcvBuf(device, core); ostringstream os; os << "EOS_POS," << nr << ",?"; int ret = ExecuteCommand(device, core, os.str().c_str()); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; ret = Acknowledge(); if (ret != DEVICE_OK) return ret; std::ostringstream os2; os2 << "Get Magnifier answer is: " << rcvBuf_; core.LogMessage(&device, os2.str().c_str(), false); pos = atoi(rcvBuf_) - 1; return DEVICE_OK; }
/* * Queries CSU for current Aperture position * 0 = Position 1 * 1 = Position 2 * *** * 9 = Position 10 */ int CSUW1Hub::GetAperturePosition(MM::Device& device, MM::Core& core, int& pos) { ClearAllRcvBuf(device, core); std::string cmd; cmd = "AP_WIDTH,1,?"; int ret = ExecuteCommand(device, core, cmd.c_str()); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; ret = Acknowledge(); if (ret != DEVICE_OK) return ret; std::ostringstream os; os << "Get Aperture answer is: " << rcvBuf_; core.LogMessage(&device, os.str().c_str(), false); pos = atoi(rcvBuf_) - 1; return DEVICE_OK; }
//TODO: Implement int CSU22Hub::GetFilterSetPosition(MM::Device& device, MM::Core& core, int &filter, int &dichroic) { ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "rsf"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; // Filter status info is in bits 1 and 2 int x = rcvBuf_[2]; x = x -'0'; filter = x & 4; // Dichroic status info is in bits 3 and 4 int y = rcvBuf_[2]; y = y -'0'; y = y >> 2; dichroic = y & 4; return DEVICE_OK; }
/* * Queries CSU for current BrightFieldPort position * 0 - Confocal * 1 - BrightfieldPort */ int CSUXHub::GetBrightFieldPort(MM::Device& device, MM::Core& core, int& pos) { ClearAllRcvBuf(device, core); std::string cmd; cmd = "BF_POS, ?"; int ret = ExecuteCommand(device, core, cmd.c_str()); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\r"); if (ret != DEVICE_OK) return ret; ret = Acknowledge(); if (ret != DEVICE_OK) return ret; std::ostringstream os; os << "Get BrightFieldPort answer is: " << rcvBuf_; core.LogMessage(&device, os.str().c_str(), false); if (strstr(rcvBuf_, "OFF") != 0) pos = 0; else pos = 1; return DEVICE_OK; }
// //TODO: Error checking int ASIFW1000Hub::GetNumberOfPositions(MM::Device& device, MM::Core& core, int wheelNr, int& nrPos) { if (wheelNr != activeWheel_) SetCurrentWheel(device, core, wheelNr); ClearAllRcvBuf(device, core); int ret = ExecuteCommand(device, core, "NF"); ret = core.GetSerialAnswer(&device, port_.c_str(), RCV_BUF_LENGTH, rcvBuf_, "\n\r"); if (ret != DEVICE_OK) return ret; if (strlen (rcvBuf_) < 2) return ERR_NO_ANSWER; // TODO: error checking nrPos = rcvBuf_[strlen(rcvBuf_)-1] - '0'; if (! (nrPos==6 || nrPos==8)) nrPos = 6; return DEVICE_OK; }