From a23382552266d3e8bca78f261e544296b6d5568c Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Thu, 30 Oct 2025 18:38:27 +0000 Subject: [PATCH 1/5] Only check soft limits on home after timeout --- GalilSup/src/GalilAxis.cpp | 12 ++- GalilSup/src/GalilConnector.cpp | 2 + GalilSup/src/GalilController.cpp | 158 +++++++++++++++++++++++-------- GalilSup/src/GalilPoller.cpp | 3 + 4 files changed, 131 insertions(+), 44 deletions(-) diff --git a/GalilSup/src/GalilAxis.cpp b/GalilSup/src/GalilAxis.cpp index e0d8b3e..dc42083 100644 --- a/GalilSup/src/GalilAxis.cpp +++ b/GalilSup/src/GalilAxis.cpp @@ -64,7 +64,7 @@ GalilAxis::GalilAxis(class GalilController *pC, //Pointer to controller instance int switch_type) //motor enable/disable switch type : asynMotorAxis(pC, (toupper(axisname[0]) - AASCII)), pC_(pC), last_encoder_position_(0), smoothed_encoder_position_(0), encoder_smooth_factor_(0.0), motor_dly_(0.0), - first_poll_(true),encDirOk_(true), pollRequest_(10, sizeof(int)) + first_poll_(true),encDirOk_(true), last_done_(1), pollRequest_(10, sizeof(int)) { string limit_code; //Code generated for limits interrupt on this axis string digital_code; //Code generated for digital interrupt related to this axis @@ -2180,7 +2180,7 @@ void GalilAxis::checkHoming(void) // ISIS: need to confirm limits high/low limit behaviour bool home_timeout = homing_ && (stoppedTime_ >= homing_timeout) && !cancelHomeSent_; - bool home_soft_limits_hit = (((readback > highLimit_ && softlimits) || (readback < lowLimit_ && softlimits)) && homing_ && !cancelHomeSent_ && done_); + bool home_soft_limits_hit = (((readback > highLimit_ && softlimits) || (readback < lowLimit_ && softlimits)) && home_timeout && done_); if (home_timeout || home_soft_limits_hit) { sprintf(pC_->cmd_, "MG homed%c\n", axisName_); @@ -2976,7 +2976,10 @@ asynStatus GalilAxis::poller(bool& moving) //Extract axis motion data from controller datarecord, and load into GalilAxis instance status |= getStatus(); - if (status) goto skip; + if (status) { + done_ = last_done_; + goto skip; + } //Set poll variables in GalilAxis based on data record info setStatus(&moving); @@ -3046,7 +3049,6 @@ asynStatus GalilAxis::poller(bool& moving) smoothed_encoder_position_ = (1.0 - encoder_smooth_factor_) * encoder_position_ + encoder_smooth_factor_ * smoothed_encoder_position_; } -skip: //Save encoder position, and done for next poll cycle last_encoder_position_ = encoder_position_; last_done_ = done_; @@ -3056,7 +3058,7 @@ asynStatus GalilAxis::poller(bool& moving) //By this driver during homing revlast_ = rev_; fwdlast_ = fwd_; - +skip: //Set status if (encoder_smooth_factor_ != 0.0) { diff --git a/GalilSup/src/GalilConnector.cpp b/GalilSup/src/GalilConnector.cpp index d461eaa..f34338d 100644 --- a/GalilSup/src/GalilConnector.cpp +++ b/GalilSup/src/GalilConnector.cpp @@ -81,6 +81,8 @@ void GalilConnector::run(void) //Check GalilController for response //Test synchronous communication //Query controller for synchronous connection handle + strcpy(pC_->cmd_, "EO 0"); // first we also turn off echo mode as it really breaks things + pC_->sync_writeReadController(); strcpy(pC_->cmd_, "WH"); sync_status = pC_->sync_writeReadController(true); //Store the handle controller used for sync diff --git a/GalilSup/src/GalilController.cpp b/GalilSup/src/GalilController.cpp index 8ed20b8..a977e82 100644 --- a/GalilSup/src/GalilController.cpp +++ b/GalilSup/src/GalilController.cpp @@ -533,6 +533,16 @@ static void signalHandler(int sig) } } +static std::string rawToEscapedString(const char* inbuf, size_t inlen) +{ + size_t outlen = epicsStrnEscapedFromRawSize(inbuf, inlen); + char* outbuf = new char[outlen + 1]; + epicsStrnEscapedFromRaw(outbuf, outlen, inbuf, inlen); + std::string s(outbuf); + delete[] outbuf; + return s; +} + //EPICS shutdown handler static void shutdownCallback(void *pPvt) { @@ -984,6 +994,7 @@ void GalilController::connect(void) address_string = address.substr(0, n); baud = atoi(address.substr(n).c_str()); } + std::cerr << "Connecting asyn port \"" << syncPort_ << "\" to serial device " << address_string << std::endl; drvAsynSerialPortConfigure(syncPort_, (const char *)address_string.c_str(), epicsThreadPriorityMax, 0, 1); if (baud != 0) { @@ -992,12 +1003,17 @@ void GalilController::connect(void) asynSetOption(syncPort_, 0, "bits", "8"); asynSetOption(syncPort_, 0, "parity", "none"); asynSetOption(syncPort_, 0, "stop", "1"); + asynSetOption(syncPort_, 0, "clocal", "Y"); // disable XON/XOFF flow control. This seemed to be required in the old driver that used the GalilTools DLL // but here it seems to lead to parts of the data record being interpreted as XOFF and getting dropped // from the readback particularly when a motor is moving. It was only enabled in the old version as otherwise // download of the homing programs timed out, but that doesn't seem to be an issue here + std::cerr << syncPort_ << ": disabling software flow control (XON/XOFF) - check this dip switch (if present) on galil controller is OFF" << std::endl; + std::cerr << syncPort_ << ": enabling hardware flow control (RTS/CTS) - check Handshake dip switch (if present) on galil controller is ON" << std::endl; asynSetOption(syncPort_, 0, "ixon", "N"); asynSetOption(syncPort_, 0, "ixoff", "N"); +// asynSetOption(syncPort_, 0, "crtscts", "Y"); + asynSetOption(syncPort_, 0, "crtscts", "N"); } //Flag try_async_ records false for serial connections try_async_ = false; @@ -1265,7 +1281,7 @@ void GalilController::connected(void) numAxesMax_ = model_[6] - ZEROASCII; else if (model_[3] == '3') //DMC30000 series numAxesMax_ = 1; - else //DMC21x3, DMC41x3, DMC40x0 + else //DMC21x3, DMC41x3, DMC40x0, DMC42x0 numAxesMax_ = model_[5] - ZEROASCII; } else //RIO PLC @@ -5147,6 +5163,7 @@ void GalilController::processUnsolicitedMesgs(void) { //Terminate the buffer rawbuf[len] = '\0'; + std::cerr << "processing unsolicited message " << rawbuf << std::endl; //Take backup before splitting into tokens string rawbufOriginal = rawbuf; //Break message into tokens: name value name value etc. @@ -5243,7 +5260,7 @@ void GalilController::processUnsolicitedMesgs(void) //Unknown message //Display message in controller console rawbufOriginal.erase(rawbufOriginal.find_last_not_of(" \n\r\t:")+1); - setCtrlError(rawbufOriginal); + setCtrlError(std::string("Unknown unsolicited message: ") + rawbufOriginal); callParamCallbacks(); //All complete break; @@ -5444,7 +5461,7 @@ bool GalilController::my_isascii(int c) asynStatus GalilController::readDataRecord(char *input, unsigned bytesize) { asynStatus status; //Asyn status - size_t nread = 0; //Asyn read bytes + size_t nread; //Asyn read bytes int eomReason; //Asyn end of message reason char buf[MAX_GALIL_DATAREC_SIZE];//Temporary buffer to hold data record in some circumstances char mesg[MAX_GALIL_STRING_SIZE] = {0x0};//Unsolicited mesg buffer @@ -5459,19 +5476,20 @@ asynStatus GalilController::readDataRecord(char *input, unsigned bytesize) for (;;) { + nread = 0; //Read bytesize using octet interface and user supplied buffer if (async_records_) status = pAsyncOctet_->read(pAsyncOctetPvt_, pasynUserAsyncGalil_, input, readsize, &nread, &eomReason); else status = pSyncOctet_->read(pSyncOctetPvt_, pasynUserSyncGalil_, input, readsize, &nread, &eomReason); - //Serial mode characters arrive with nread = 1 + //Serial mode characters can arrive with nread = 1 but also with nread > 1 but less than readsize //UDP async mode unsolicited mesg always cause read (above) to return with nread set to mesg length //TCP sync mode unsolicited mesg sometimes cause read to return with nread set to mesg length //TCP sync mode unsolicited mesg mostly cause read to return with nread = readsize //Readsize varies when reading data record tail in tcp sync with unsolicited message - if (nread == bytesize && eomReason == ASYN_EOM_CNT) + if (!status && nread == bytesize && eomReason == ASYN_EOM_CNT) { //Read returned ok, with expected bytes //Look for record header at expected location in buffer @@ -5480,9 +5498,13 @@ asynStatus GalilController::readDataRecord(char *input, unsigned bytesize) //Record header cannot be found here in rs232 mode check = (unsigned char)input[3] << 8; check = (unsigned char)input[2] + check; - if (check == datarecsize_) + if (input[1] & 0x80 != 0 && check == datarecsize_) { + if (j > 0) { + std::cerr << "readDataRecord(): discarding message " << mesg << " length " << j << std::endl; + } return status;//Found record at expected location, job done } + } if (!status && nread > 0) { @@ -5505,15 +5527,13 @@ asynStatus GalilController::readDataRecord(char *input, unsigned bytesize) { //Detected record header recstart = true; - if (nread == bytesize && eomReason == ASYN_EOM_CNT) - { - //Received expected number of bytes, but didn't find header at expected location - //Not a serial connection, so it must be synchronous tcp - //This means the header is not at expected location due to unsolicited message - //Store buffer index where datarecord header starts - //Which is also number of data record bytes remaining (tail) to read - readsize = i - HEADER_BYTES + 1; - } + //either Received expected number of bytes, but didn't find header at expected location + //or read less bytes than expected. need to queue an extra read for later after prcoessing these bytes + //This means the header is not at expected location due to unsolicited message + // we read nread and header started at offset (i - HEADER_BYTES + 1) + int offset_to_header = i - HEADER_BYTES + 1; // location of found header in current input buffer + readsize = bytesize + offset_to_header; // nread will be subtracted later + memcpy(buf, input + offset_to_header, HEADER_BYTES); } if (!recstart) { @@ -5556,6 +5576,12 @@ asynStatus GalilController::readDataRecord(char *input, unsigned bytesize) //Data record read complete //Copy data record into user supplied buffer memcpy(input, buf, bytesize); + if (j > 0) { + std::cerr << "readDataRecord(): discarding message " << mesg << " length " << j << std::endl; + } + if (i != nread-1) { + std::cerr << "readDataRecord(): i error" << std::endl; + } return status; } } @@ -5565,8 +5591,13 @@ asynStatus GalilController::readDataRecord(char *input, unsigned bytesize) previous = input[nread - 1]; //Loop back and keep reading until we get the data record or error } - else - return asynError;//Stop if any asyn error + else { + if (j > 0) { + std::cerr << "readDataRecord(): discarding message " << mesg << " length " << j << std::endl; + } + return asynError;//Stop if any asyn error + } + readsize -= nread; } } @@ -5592,8 +5623,11 @@ void GalilController::acquireDataRecord(void) strcpy(cmd_, "QR\r"); //Write the QR query to controller recstatus_ = pSyncOctet_->write(pSyncOctetPvt_, pasynUserSyncGalil_, cmd_, 3, &nwrite); - if (!recstatus_) //Solicited data record includes an extra colon at the end + if (!recstatus_) {//Solicited data record includes an extra colon at the end recstatus_ = readDataRecord(resp_, datarecsize_ + 1); //Get the record + } else { + std::cerr << "acquireDataRecord: failed to send QR" << std::endl; + } unlock(); } else //Asynchronous poll @@ -5608,8 +5642,10 @@ void GalilController::acquireDataRecord(void) } //Track timeouts - if (recstatus_ != asynSuccess) + if (recstatus_ != asynSuccess) { consecutive_acquire_timeouts_++; + std::cerr << "acquireDataRecord: data record acquire timeout number " << consecutive_acquire_timeouts_ << std::endl; + } //Force disconnect if any errors if (consecutive_acquire_timeouts_ > ALLOWED_TIMEOUTS) @@ -5639,7 +5675,7 @@ void GalilController::acquireDataRecord(void) asynStatus GalilController::sync_writeReadController(bool testQuery, bool logCommand) { const char *functionName="sync_writeReadController"; - size_t nread; + size_t nread = 0; int status; size_t len; static const char* debug_file_name = macEnvExpand("$(GALIL_DEBUG_FILE=)"); @@ -5708,12 +5744,14 @@ asynStatus GalilController::sync_writeReadController(const char *output, char *i unsigned i = 0; //Number of raw bytes received, general counting unsigned j = 0; //Number of unsolicited bytes received unsigned k = 0; //Number of solicited bytes received - size_t nwrite; //Bytes written + unsigned m = 0; //Number of discarded bytes received + size_t nwrite = 0; //Bytes written asynStatus status = asynSuccess;//Asyn status int eomReason; //End of message reason char buf[MAX_GALIL_DATAREC_SIZE] = ""; //Receive buffer char mesg[MAX_GALIL_DATAREC_SIZE] = ""; //Unsolicited buffer char resp[MAX_GALIL_DATAREC_SIZE] = ""; //Solicited buffer + char discard[MAX_GALIL_DATAREC_SIZE] = ""; //discard buffer string inp = ""; //Solicited data concatenated over multiple reads //Sometimes caller puts many commands on one line separated by ; so we must string out_string = output; //Determine number of output terminators to search for from requested command @@ -5721,7 +5759,10 @@ asynStatus GalilController::sync_writeReadController(const char *output, char *i int found_terminators = 0; //Terminator characters found so far unsigned char value; //Used to identify unsolicited traffic bool done = false; //Read complete? + bool term_done = false; // found all terminators? + size_t this_nread; + *nread = 0; //Null user supplied input buffer strcpy(input, ""); //Set timeout for Sync connection @@ -5734,12 +5775,13 @@ asynStatus GalilController::sync_writeReadController(const char *output, char *i while (!done) { //Read any response - status = pSyncOctet_->read(pSyncOctetPvt_, pasynUserSyncGalil_, buf, MAX_GALIL_DATAREC_SIZE, nread, &eomReason); + this_nread = 0; + status = pSyncOctet_->read(pSyncOctetPvt_, pasynUserSyncGalil_, buf, MAX_GALIL_DATAREC_SIZE, &this_nread, &eomReason); //If read successful, search for terminator characters - if (!status && *nread > 0) + if (!status && this_nread > 0) { //Search for terminating characters - for (i = 0; i < *nread; i++) + for (i = 0; i < this_nread; i++) { //Controller responds with ? or : for each command separated by ; if (buf[i] == '?') @@ -5765,35 +5807,72 @@ asynStatus GalilController::sync_writeReadController(const char *output, char *i mesg[j++] = (unsigned char)value; //Terminate the buffers mesg[j] = '\0'; + //Send unsolicited message if last char was line feed + if (mesg[j - 1] == '\n') + { + sendUnsolicitedMessage(mesg); + mesg[0] = '\0'; + j = 0; + } } else { //Byte looks like a solicited packet - //Check for overrun - if (k > MAX_GALIL_DATAREC_SIZE - 2) - return asynError;//No solicited message should be this long return error - resp[k++] = buf[i];//Byte is part of solicited message - //Terminate the buffer - resp[k] = '\0'; + if (!term_done) + { + //Check for overrun + if (k > MAX_GALIL_DATAREC_SIZE - 2) + return asynError;//No solicited message should be this long return error + resp[k++] = buf[i];//Byte is part of solicited message + //Terminate the buffer + resp[k] = '\0'; + } else { + discard[m++] = buf[i]; + discard[m] = '\0'; + } + if (found_terminators == target_terminators) { + term_done = true; + } + } + } + if (found_terminators > target_terminators) + { + std::cerr << "sync_writeReadController(): Found " << found_terminators - target_terminators << " more terminators than expected" << std::endl; } //If received all expected terminators, read is complete - if (found_terminators == target_terminators) + if (term_done) { //Don't attempt any more reads done = true; //stop searching this read, and return the resp, then send unsolicited mesg break; } - } } else //Stop read if any asyn error + { + if (j != 0) { + std::cerr << "sync_writeReadController(): after error - Discarded unsolicited message: " << mesg << " length " << j << std::endl; + } + if (m != 0) { + std::cerr << "sync_writeReadController(): after error - Discarded bytes: " << rawToEscapedString(discard, m) << " length " << m << std::endl; + } return asynError; + } }//while (!done) //Copy solicited response into user supplied buffer strcpy(input, resp); - //Send unsolicited mesg to queue - if (j != 0) - sendUnsolicitedMessage(mesg); + *nread = strlen(resp); + //Check for any remaining unsolicited messages + //Any here did not end in a \n - discard or send anyway? + if (j != 0) { + std::cerr << "sync_writeReadController(): after success - Discarded unsolicited message: " << mesg << " length " << j << std::endl; + std::cerr << "\"" << output << "\" \"" << input << "\"" << std::endl; + //sendUnsolicitedMessage(mesg); + } + if (m != 0) { + std::cerr << "sync_writeReadController(): after success - Discarded bytes: " << rawToEscapedString(discard, m) << " length " << m << std::endl; + std::cerr << "\"" << output << "\" \"" << input << "\"" << std::endl; + } }//write ok return status; } @@ -6657,9 +6736,9 @@ void GalilController::GalilStartController(char *code_file, int burn_program, in timeout_ = 10; //Upload code currently in controller for comparison to generated/user code status = programUpload(&uc); - if (status) //Upload failed - errlogPrintf("\nError uploading code model %s, address %s\n",model_.c_str(), address_.c_str()); - + if (status) { //Upload failed + errlogPrintf("\nError uploading code for comparison, model %s, address %s\nWill assume any on controller code is outdated\n",model_.c_str(), address_.c_str()); + } if ((display_code == 2) || (display_code == 3)) { //Print out the uploaded code from the controller printf("\nUploaded code is\n\n"); @@ -6753,7 +6832,7 @@ void GalilController::GalilStartController(char *code_file, int burn_program, in uc.push_back('\r'); } else { - errlogPrintf("\nError uploading code model %s, address %s\n",model_.c_str(), address_.c_str()); + errlogPrintf("\nError uploading code after transfer to verify, model %s, address %s\n",model_.c_str(), address_.c_str()); } //Start thread 0 if code on controller matches what was downloaded @@ -7232,6 +7311,7 @@ void GalilController::InitializeDataRecord(void) axis_b = atoi(charstr); //Store the data record size datarecsize_ = HEADER_BYTES + (axes * axis_b) + general_b + coord_b; + std::cerr << "Galil data record is " << datarecsize_ << " bytes in size" << std::endl; //DMC300x0 returns 1 18 16 36, search for "DMC31" in model string to determine 16bit ADC if (general_b == 18) return Init30010(model.find("DMC31") != string::npos); //DMC40x0/DMC41x3/DMC50000 8 52 26 36 diff --git a/GalilSup/src/GalilPoller.cpp b/GalilSup/src/GalilPoller.cpp index 2c8aec8..5c6ca10 100644 --- a/GalilSup/src/GalilPoller.cpp +++ b/GalilSup/src/GalilPoller.cpp @@ -232,6 +232,9 @@ void GalilPoller::wakePoller(bool restart_async) //Set most signficant bit for unsolicited bytes strcpy(pC_->cmd_, "CW 1"); status = pC_->sync_writeReadController(); + // set program behaviour on fifo full + strcpy(pC_->cmd_, "CW ,0"); + status = pC_->sync_writeReadController(); } } } From c2cda216600cdffc95a9646574456928b1c4d15d Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Thu, 18 Jun 2026 22:41:26 +0100 Subject: [PATCH 2/5] jj --- GalilSup/src/GalilAxis.cpp | 2 +- GalilSup/src/GalilController.cpp | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/GalilSup/src/GalilAxis.cpp b/GalilSup/src/GalilAxis.cpp index dc42083..a524f3f 100644 --- a/GalilSup/src/GalilAxis.cpp +++ b/GalilSup/src/GalilAxis.cpp @@ -2189,7 +2189,7 @@ void GalilAxis::checkHoming(void) if (homed == 1) { - std::cerr << "Looks like homing completed OK but unsolicited message from controller got lost" << std::endl; + std::cerr << "Looks like homing completed OK but unsolicited message from controller got lost for axis " << axisName_ << std::endl; // execute logic as per GalilController::processUnsolicitedMesgs this->homedExecuted_ = false; this->pollRequest_.send((void*)&MOTOR_HOMED, sizeof(int)); diff --git a/GalilSup/src/GalilController.cpp b/GalilSup/src/GalilController.cpp index a977e82..6a26b80 100644 --- a/GalilSup/src/GalilController.cpp +++ b/GalilSup/src/GalilController.cpp @@ -5163,7 +5163,6 @@ void GalilController::processUnsolicitedMesgs(void) { //Terminate the buffer rawbuf[len] = '\0'; - std::cerr << "processing unsolicited message " << rawbuf << std::endl; //Take backup before splitting into tokens string rawbufOriginal = rawbuf; //Break message into tokens: name value name value etc. @@ -5624,7 +5623,11 @@ void GalilController::acquireDataRecord(void) //Write the QR query to controller recstatus_ = pSyncOctet_->write(pSyncOctetPvt_, pasynUserSyncGalil_, cmd_, 3, &nwrite); if (!recstatus_) {//Solicited data record includes an extra colon at the end + if (true /*rand() % 100 != 0*/) { recstatus_ = readDataRecord(resp_, datarecsize_ + 1); //Get the record + } else { + recstatus_ = asynTimeout; + } } else { std::cerr << "acquireDataRecord: failed to send QR" << std::endl; } @@ -5866,12 +5869,12 @@ asynStatus GalilController::sync_writeReadController(const char *output, char *i //Any here did not end in a \n - discard or send anyway? if (j != 0) { std::cerr << "sync_writeReadController(): after success - Discarded unsolicited message: " << mesg << " length " << j << std::endl; - std::cerr << "\"" << output << "\" \"" << input << "\"" << std::endl; + //std::cerr << "\"" << output << "\" \"" << input << "\"" << std::endl; //sendUnsolicitedMessage(mesg); } if (m != 0) { std::cerr << "sync_writeReadController(): after success - Discarded bytes: " << rawToEscapedString(discard, m) << " length " << m << std::endl; - std::cerr << "\"" << output << "\" \"" << input << "\"" << std::endl; + //std::cerr << "\"" << output << "\" \"" << input << "\"" << std::endl; } }//write ok return status; From c7dc2437360f826621e3fa952683476a97bedf0e Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 8 Jun 2026 12:45:10 +0100 Subject: [PATCH 3/5] Try to avoid race condition on startup --- GalilSup/Db/galil_dmc_ctrl.template | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/GalilSup/Db/galil_dmc_ctrl.template b/GalilSup/Db/galil_dmc_ctrl.template index aba380c..0713eae 100644 --- a/GalilSup/Db/galil_dmc_ctrl.template +++ b/GalilSup/Db/galil_dmc_ctrl.template @@ -591,7 +591,11 @@ record(ao,"$(P)PWRDET:SP") { field(DTYP, "asynFloat64") field(OUT, "@asyn($(PORT),0)USER_VAR pwrdet") field(SCAN, "Passive") + # set a default non-zero as zero in galil is a problem + # and is never a test value + field(VAL, "2") info(autosaveFields_pass0, "VAL") + info(archive, "VAL") } record(ai,"$(P)PWRDET") { @@ -599,7 +603,9 @@ record(ai,"$(P)PWRDET") { field(DTYP, "asynFloat64") field(INP, "@asyn($(PORT),0)USER_VAR pwrdet") field(SCAN, "10 second") + field(SDIS, "$(P)PWRDET:SP.PACT") field(FLNK, "$(P)PWRDET:ALERT.PROC") + info(archive, "VAL") } ## 0 = ok, 1 = problem @@ -610,7 +616,7 @@ record(calcout,"$(P)PWRDET:ALERT") { field(INPB, "$(P)PWRDET:SP") field(CALC, "A!=B") field(OOPT, "When Zero") - field(OUT, "$(P)PWRDET:TIMER.PROC") + field(OUT, "$(P)PWRDET:TIMER.PROC PP") info(archive, "VAL") } @@ -622,12 +628,16 @@ record(bo,"$(P)PWRDET:RESET:SP") { } ## how often we should set a new test value -## A % 360 means 3600 seconds as we are on 10 second scan link +## A = 360 means 3600 seconds as we are on 10 second scan link +## Changing value is only a check in case it got saved into galil +## firmware so changing this once per ioc run is fine +## make sure we don't set a new value too soon +## after ioc startup in case of a quick restart causing a race condition record(calcout, "$(P)PWRDET:TIMER") { field(DESC, "Set new PWRDET test value") - field(CALC, "A % 360; A := A + 1") + field(CALC, "A = 360; A := A + 1") field(INPA, "0") - field(OOPT, "When Zero") + field(OOPT, "When Non-zero") field(DOPT, "Use OCAL") field(OCAL, "CEIL(RNDM*100)+1") field(OUT, "$(P)PWRDET:SP PP") From 123ec978dac1c062bfd10c2af2bea3aeb261df38 Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Fri, 19 Jun 2026 00:13:47 +0100 Subject: [PATCH 4/5] Add kinematics request file --- GalilSup/Db/GALIL_controller_kinematics.req | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 GalilSup/Db/GALIL_controller_kinematics.req diff --git a/GalilSup/Db/GALIL_controller_kinematics.req b/GalilSup/Db/GALIL_controller_kinematics.req new file mode 100644 index 0000000..418efff --- /dev/null +++ b/GalilSup/Db/GALIL_controller_kinematics.req @@ -0,0 +1,21 @@ +# Kinematics + +# Forward transforms (Readbacks) +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)09 +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)10 +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)11 +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)12 +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)13 +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)14 +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)15 +file "galil_forward_transform.req" P=$(P), M=MTR$(CCP)16 + +# Reverse transforms (Setpoints) +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)09 +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)10 +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)11 +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)12 +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)13 +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)14 +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)15 +file "galil_reverse_transforms.req" P=$(P), M=MTR$(CCP)16 From f1bd13dca21ede9ea52c9cc15fddc370cae2e10d Mon Sep 17 00:00:00 2001 From: Freddie Akeroyd Date: Mon, 22 Jun 2026 14:31:21 +0100 Subject: [PATCH 5/5] p --- GalilSup/Db/galil_Home_Dummy_Move.dmc | 20 +++++++++++++------- GalilSup/Db/galil_motor_extras.template | 2 +- GalilSup/src/GalilAxis.cpp | 4 +++- 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/GalilSup/Db/galil_Home_Dummy_Move.dmc b/GalilSup/Db/galil_Home_Dummy_Move.dmc index 128127d..4da4b61 100644 --- a/GalilSup/Db/galil_Home_Dummy_Move.dmc +++ b/GalilSup/Db/galil_Home_Dummy_Move.dmc @@ -13,18 +13,24 @@ IF (home${AXIS}=1) IF ((hjog${AXIS}=1) & (_BG${AXIS}=1) & (home${AXIS}=1)) ST${AXIS};ENDIF IF ((hjog${AXIS}=1) & (_BG${AXIS}=0) & (home${AXIS}=1)) - PR${AXIS}=(_SP${AXIS} * 2);SH${AXIS};WT100;BG${AXIS};hjog${AXIS}=2 + PR${AXIS}=(_SP${AXIS} * 2);SH${AXIS};hjog${AXIS}=2 ENDIF - IF ((hjog${AXIS}=2) & (_BG${AXIS}=0) & (home${AXIS}=1) & (_SC${AXIS}=1)) - hjog${AXIS}=3 + IF ((hjog${AXIS}=2) & (_BG${AXIS}=0) & (_MO${AXIS}=0) & (home${AXIS}=1)) + BG${AXIS};hjog${AXIS}=3 + ENDIF + IF ((hjog${AXIS}=3) & (_BG${AXIS}=0) & (home${AXIS}=1) & (_SC${AXIS}=1)) + hjog${AXIS}=4 ENDIF - IF ((hjog${AXIS}>=3) & (hjog${AXIS}<10) & (_BG${AXIS}=0) & (home${AXIS}=1)) + IF ((hjog${AXIS}>=4) & (hjog${AXIS}<11) & (_BG${AXIS}=0) & (home${AXIS}=1)) hjog${AXIS}=hjog${AXIS}+1;WT10 ENDIF - IF ((hjog${AXIS}=10) & (_BG${AXIS}=0) & (home${AXIS}=1)) - PR${AXIS}=(_SP${AXIS} * -2);SH${AXIS};WT100;BG${AXIS};hjog${AXIS}=11 + IF ((hjog${AXIS}=11) & (_BG${AXIS}=0) & (home${AXIS}=1)) + PR${AXIS}=(_SP${AXIS} * -2);SH${AXIS};hjog${AXIS}=12 ENDIF - IF ((hjog${AXIS}=11) & (_BG${AXIS}=0) & (home${AXIS}=1) & (_SC${AXIS}=1)) + IF ((hjog${AXIS}=12) & (_BG${AXIS}=0) & (_MO${AXIS}=0) & (home${AXIS}=1)) + BG${AXIS};hjog${AXIS}=13 + ENDIF + IF ((hjog${AXIS}=13) & (_BG${AXIS}=0) & (home${AXIS}=1) & (_SC${AXIS}=1)) hjog${AXIS}=0;home${AXIS}=0;homed${AXIS}=1 MG "home${AXIS}", home${AXIS};MG "homed${AXIS}", homed${AXIS} ENDIF diff --git a/GalilSup/Db/galil_motor_extras.template b/GalilSup/Db/galil_motor_extras.template index 2417cdc..9a9190b 100644 --- a/GalilSup/Db/galil_motor_extras.template +++ b/GalilSup/Db/galil_motor_extras.template @@ -271,7 +271,7 @@ record(bo,"$(P)$(M)_USWITCH_CMD") { field(DESC,"use switch") field(DTYP,"asynInt32") - field(VAL, "1") + field(VAL, "0") field(PINI,"YES") field(ZNAM,"No") field(ZSV, "NO_ALARM") diff --git a/GalilSup/src/GalilAxis.cpp b/GalilSup/src/GalilAxis.cpp index a524f3f..5e83e7e 100644 --- a/GalilSup/src/GalilAxis.cpp +++ b/GalilSup/src/GalilAxis.cpp @@ -2046,6 +2046,8 @@ void GalilAxis::checkEncoder(void) double sc_code = getGalilAxisVal("_SC"); // get axis moving state double bg_code = getGalilAxisVal("_BG"); + // in case we are homing record hjog + int hjog_code = getGalilAxisVal("hjog"); //Pass stall status to higher layers setIntegerParam(pC_->motorStatusSlip_, 1); //Set the stop reason so limit deceleration is applied during stop @@ -2058,7 +2060,7 @@ void GalilAxis::checkEncoder(void) sprintf(message, "Encoder stall stop motor %c", axisName_); //Set controller error mesg monitor pC_->setCtrlError(message); - std::cerr << "STALL: pestall_time=" << pestall_time << " (>" << estall_time << ") encoderMove_=" << encoderMove_ << " encDirOk_=" << encDirOk_ << " _SC" << axisName_ << "=" << sc_code << " [" << lookupStopCode((int)sc_code) << "] _BG" << axisName_ << "=" << bg_code << std::endl; + std::cerr << "STALL: pestall_time=" << pestall_time << " (>" << estall_time << ") encoderMove_=" << encoderMove_ << " encDirOk_=" << encDirOk_ << " _SC" << axisName_ << "=" << sc_code << " [" << lookupStopCode((int)sc_code) << "] _BG" << axisName_ << "=" << bg_code << " hjog" << axisName_ << "=" << hjog_code << std::endl; } } }