Hi Mark,
Here is the code. I tried to send the whole IOC, but your mailer rejected it.
Pete.
From: Mark Rivers <rivers at cars.uchicago.edu>
Sent: Tuesday, December 8, 2020 2:36 PM
To: Siddons, David <siddons at bnl.gov>
Cc: tech-talk at aps.anl.gov <tech-talk at aps.anl.gov>
Subject: RE: multiple USB devices in Asyn
Hi Pete,
Where is the source code containing this driver?
almCreateEZ4Controller("ALM1", "IP1", "$(ALM_ADDR1)", 4, 200, 500)
Mark
From: Tech-talk <tech-talk-bounces at aps.anl.gov>
On Behalf Of Siddons, David via Tech-talk
Sent: Tuesday, December 8, 2020 1:13 PM
To: tech-talk at aps.anl.gov
Subject: multiple USB devices in Asyn
I have a setup with two identical USB devices. They connect as ttyUSB0 and ttyUSB1. I tried to set up an asyn interface using the following commands:
drvAsynSerialPortConfigure("IP1", "/dev/ttyUSB0", 0, 0, 0)
asynSetOption("IP1", -1, "baud", "115200")
asynSetOption("IP1", -1, "bits", "8")
asynSetOption("IP1", -1, "parity", "none")
asynSetOption("IP1", -1, "stop", "1")
asynSetOption("IP1", -1, "clocal", "Y")
asynSetOption("IP1", -1, "crtscts", "N")
drvAsynSerialPortConfigure("IP2", "/dev/ttyUSB1", 0, 0, 0)
asynSetOption("IP2", -1, "baud", "115200")
asynSetOption("IP2", -1, "bits", "8")
asynSetOption("IP2", -1, "parity", "none")
asynSetOption("IP2", -1, "stop", "1")
asynSetOption("IP2", -1, "clocal", "Y")
asynSetOption("IP2", -1, "crtscts", "N")
# almCreateController(AllMotion port name, asyn port name, board address,
# Number of axes, Moving poll period (ms), Idle poll period (ms))
almCreateEZ4Controller("ALM1", "IP1", "$(ALM_ADDR1)", 4, 200, 500)
almCreateEZ4Controller("ALM2", "IP2", "$(ALM_ADDR2)", 4, 200, 500)
This fails, saying port ALM2 cannot be found. If I try to connect the second one also to ALM1, it complains that ALM1 is already registered.
If I comment out the first device, the second one (with port ALM2) comes up fine. How should I be doing this?
|
/*
* AllMotion controller
* */
// vim: tabstop=2 shiftwidth=2
#include "allmotion.h"
static const char *ALM_PSTR_THRESH[] = {
ALM_PSTR_INPUT_THRESHOLD0,
ALM_PSTR_INPUT_THRESHOLD1,
ALM_PSTR_INPUT_THRESHOLD2,
ALM_PSTR_INPUT_THRESHOLD3
};
static const char *ALM_PSTR_LIM_THRESH[] = {
ALM_PSTR_LIMIT_THRESH_HIGH,
ALM_PSTR_LIMIT_THRESH_LOW
};
static const char *ALM_PSTR_PROG[] = {
ALM_PSTR_PROG_0,
ALM_PSTR_PROG_1,
ALM_PSTR_PROG_2,
ALM_PSTR_PROG_3,
ALM_PSTR_PROG_4,
ALM_PSTR_PROG_5,
ALM_PSTR_PROG_6,
ALM_PSTR_PROG_7,
ALM_PSTR_PROG_8,
ALM_PSTR_PROG_9,
ALM_PSTR_PROG_10,
ALM_PSTR_PROG_11,
ALM_PSTR_PROG_12,
ALM_PSTR_PROG_13,
ALM_PSTR_PROG_14,
ALM_PSTR_PROG_15
};
/** Creates a new almController object.
* \param[in] portName The name of the asyn port that will be created for this driver
* \param[in] asynPort The name of the drvAsynIPPPort that was created previously to connect to the controller
* \param[in] address The address of the device on the RS485 bus
* \param[in] numAxes The number of axes that this controller supports
* \param[in] movingPollPeriod The time between polls when any axis is moving
* \param[in] idlePollPeriod The time between polls when no axis is moving
*/
almController::almController(const char *portName, const char *asynPortName, int address,
int numAxes, double movingPollPeriod, double idlePollPeriod)
: asynMotorController(portName, numAxes, NUM_ALM_PARAMS,
asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask | asynOctetMask,
asynInt32Mask | asynFloat64Mask | asynUInt32DigitalMask | asynOctetMask,
ASYN_CANBLOCK | ASYN_MULTIDEVICE,
1, // autoconnect
0, 0) // Default priority and stack size
{
int i;
address_ = address;
idlePollPeriod_ = idlePollPeriod;
movingPollPeriod_ = movingPollPeriod;
for (i=0; i < ALM_AXES; i++) {
positions_[i] = 0;
velocities_[i] = 0;
encoder_positions_[i] = 0;
}
for (i=0; i < ALM_INPUT_COUNT; i++) {
thresholds_[i] = 0;
adc_[i] = 0.0;
}
ready_ = true;
// TODO: timeout being too slow could eventually be an issue
// in writeRead() need to recv() while checking for ALM_OEM_START/ALM_OEM_STOP
// with a lower timeout
timeout_ = 0.1;
response_code_ = ALM_NO_ERROR;
if (!addToList(portName, this)) {
printf("%s:%s: Init failed", driverName, portName);
return;
}
// Write-only
createParam(ALM_PSTR_KILL_ALL , asynParamInt32, ¶m_kill_all_);
createParam(ALM_PSTR_READ_ADC , asynParamInt32, ¶m_read_adc_);
createParam(ALM_PSTR_READ_INP , asynParamInt32, ¶m_read_inp_);
createParam(ALM_PSTR_READ_THRESH , asynParamInt32, ¶m_read_thresh_);
createParam(ALM_PSTR_READ_LIM_THR , asynParamInt32, ¶m_read_limit_thresh_);
createParam(ALM_PSTR_PROG_RUN , asynParamInt32, ¶m_prog_run_);
for (i=0; i < ALM_PROG_COUNT; i++) {
createParam(ALM_PSTR_PROG[i], asynParamOctet, ¶m_prog_[i]);
}
createParam(ALM_PSTR_PROG_IDX , asynParamInt32, ¶m_prog_idx_);
createParam(ALM_PSTR_PROG_WRITE , asynParamOctet, ¶m_prog_write_);
createParam(ALM_PSTR_MODE , asynParamUInt32Digital, ¶m_mode_);
createParam(ALM_PSTR_SP_MODE , asynParamUInt32Digital, ¶m_sp_mode_);
createParam(ALM_PSTR_DRIVER1_POWER , asynParamInt32, ¶m_driver1_power_);
createParam(ALM_PSTR_DRIVER2_POWER , asynParamInt32, ¶m_driver2_power_);
createParam(ALM_PSTR_SWITCH_DEBOUNCE , asynParamInt32, ¶m_switch_debounce_);
createParam(ALM_PSTR_DAUGHTER_CURRENT , asynParamInt32, ¶m_daughter_current_);
createParam(ALM_PSTR_DAUGHTER_CUR_FLOW , asynParamInt32, ¶m_daughter_cur_flow_);
createParam(ALM_PSTR_POT_OFFSET , asynParamInt32, ¶m_pot_offset_);
createParam(ALM_PSTR_POT_MUL , asynParamInt32, ¶m_pot_mul_);
createParam(ALM_PSTR_POT_DEADBAND , asynParamInt32, ¶m_pot_deadband_);
createParam(ALM_PSTR_ENC_OUTER_DB , asynParamInt32, ¶m_enc_outer_db_);
createParam(ALM_PSTR_ENC_INNER_DB , asynParamInt32, ¶m_enc_inner_db_);
createParam(ALM_PSTR_ENC_RATIO , asynParamInt32, ¶m_enc_ratio_);
createParam(ALM_PSTR_OVERLOAD_TIMEOUT , asynParamInt32, ¶m_overload_timeout_);
createParam(ALM_PSTR_INT_PERIOD , asynParamInt32, ¶m_int_period_);
createParam(ALM_PSTR_RECOVERY_RUNS , asynParamInt32, ¶m_recovery_runs_);
createParam(ALM_PSTR_HOME_POLARITY , asynParamInt32, ¶m_home_polarity_);
createParam(ALM_PSTR_RESET , asynParamInt32, ¶m_reset_);
createParam(ALM_PSTR_INVERT_INPUT0 , asynParamInt32, ¶m_invert_input_[0]);
createParam(ALM_PSTR_INVERT_INPUT1 , asynParamInt32, ¶m_invert_input_[1]);
createParam(ALM_PSTR_INVERT_INPUT2 , asynParamInt32, ¶m_invert_input_[2]);
createParam(ALM_PSTR_INVERT_INPUT3 , asynParamInt32, ¶m_invert_input_[3]);
createParam(ALM_PSTR_MICROSTEP_TWEAK , asynParamInt32, ¶m_microstep_tweak_);
createParam(ALM_PSTR_MAX_AMPS , asynParamFloat64, ¶m_max_amps_);
// Read-only
createParam(ALM_PSTR_ADC_1 , asynParamFloat64, ¶m_adc_[0]);
createParam(ALM_PSTR_ADC_2 , asynParamFloat64, ¶m_adc_[1]);
createParam(ALM_PSTR_ADC_3 , asynParamFloat64, ¶m_adc_[2]);
createParam(ALM_PSTR_ADC_4 , asynParamFloat64, ¶m_adc_[3]);
createParam(ALM_PSTR_ENC_1 , asynParamInt32, ¶m_enc_[0]);
createParam(ALM_PSTR_ENC_2 , asynParamInt32, ¶m_enc_[1]);
createParam(ALM_PSTR_INP_SW1 , asynParamInt32, ¶m_inp_sw1_);
createParam(ALM_PSTR_INP_SW2 , asynParamInt32, ¶m_inp_sw2_);
createParam(ALM_PSTR_INP_OPTO1 , asynParamInt32, ¶m_inp_opto1_);
createParam(ALM_PSTR_INP_OPTO2 , asynParamInt32, ¶m_inp_opto2_);
createParam(ALM_PSTR_INP_CHA , asynParamInt32, ¶m_inp_cha_);
createParam(ALM_PSTR_INP_CHB , asynParamInt32, ¶m_inp_chb_);
createParam(ALM_PSTR_INP_IDX , asynParamInt32, ¶m_inp_idx_);
createParam(ALM_PSTR_FIRMWARE , asynParamOctet, ¶m_firmware_);
createParam(ALM_PSTR_ERROR , asynParamOctet, ¶m_error_);
// Read-write
createParam(ALM_PSTR_MICROSTEPS , asynParamInt32, ¶m_microsteps_);
for (i=0; i < ALM_INPUT_COUNT; i++) {
createParam(ALM_PSTR_THRESH[i], asynParamFloat64, ¶m_input_threshold_[i]);
}
createParam(ALM_PSTR_LIMIT_INVERT , asynParamInt32, ¶m_limit_invert_);
for (i=0; i < 2; i++) {
createParam(ALM_PSTR_LIM_THRESH[i], asynParamFloat64, ¶m_limit_thresh_[i]);
}
// Read-write
createParam(ALM_PSTR_HOLD_I , asynParamFloat64, ¶m_hold_i_);
createParam(ALM_PSTR_MOVE_I , asynParamFloat64, ¶m_move_i_);
#if 0
const char *pname;
for (i=0; i < 100; i++) {
getParamName(i, &pname);
printf("%d %s\n", i, pname);
}
#endif
setStringParam(param_error_, "");
setIntegerParam(motorStatusHasEncoder_, 1);
// TODO other drives different?
setDoubleParam(param_max_amps_, 2.0);
/* Connect to the AllMotion controller */
asynStatus status = pasynOctetSyncIO->connect(asynPortName, 0, &pasynUser_, NULL);
if (status) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
"%s:%s: cannot connect to AllMotion controller\n",
driverName, __func__);
}
status = pasynOctetSyncIO->setInputEos(pasynUser_, ALM_INPUT_EOS, 1);
if (status) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR|ASYN_TRACE_FLOW,
"%s: Unable to set input EOS on %s: %s\n",
__func__, asynPortName, pasynUser_->errorMessage);
}
status = pasynOctetSyncIO->setOutputEos(pasynUser_, ALM_OUTPUT_EOS, 1);
if (status) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR|ASYN_TRACE_FLOW,
"%s: Unable to set output EOS on %s: %s\n",
__func__, asynPortName, pasynUser_->errorMessage);
}
// Create the axis objects
for (int axis=0; axis<numAxes; axis++) {
new almAxis(this, axis);
}
startPoller(movingPollPeriod/1000., idlePollPeriod/1000., 2);
queryFirmware();
queryInputs();
getInputThresholds();
getLimitThresholds();
}
asynStatus almController::queryPositions() {
almResponsePacket response;
asynStatus status = asynSuccess;
for (int axis=0; axis < numAxes_; axis++) {
if (queryParameter(axis, ALM_QUERY_POS, response) == asynSuccess)
positions_[axis] = response.as_int();
else
status = asynError;
}
return status;
}
asynStatus almController::queryVelocities() {
almResponsePacket response;
asynStatus status = asynSuccess;
for (int axis=0; axis<numAxes_; axis++) {
if (queryParameter(axis, ALM_QUERY_VELOCITY, response) == asynSuccess)
velocities_[axis] = response.as_int();
else
status = asynError;
}
return status;
}
asynStatus almController::queryEncoders() {
almResponsePacket response;
asynStatus status = asynSuccess;
if (queryControllerParam(ALM_QUERY_ENC_1, response) == asynSuccess) {
encoder_positions_[0] = response.as_int();
encoder_positions_[2] = response.as_int();
} else {
status = asynError;
}
if (queryControllerParam(ALM_QUERY_ENC_2, response) == asynSuccess) {
encoder_positions_[1] = response.as_int();
encoder_positions_[3] = response.as_int();
} else {
status = asynError;
}
return status;
}
asynStatus almController::poll()
{
asynStatus status = asynSuccess;
asynStatus st;
if ((st = queryPositions()) != asynSuccess)
status = st;
if ((st = queryVelocities()) != asynSuccess)
status = st;
if ((st = queryEncoders()) != asynSuccess)
status = st;
return status;
}
/** Called when asyn clients call pasynFloat64->write().
* Extracts the function and axis number from pasynUser.
* Sets the value in the parameter library.
* Calls any registered callbacks for this pasynUser->reason and address.
*
* \param[in] pasynUser asynUser structure that encodes the reason and address.
* \param[in] value Value to write. */
asynStatus almController::writeFloat64(asynUser *pasynUser, epicsFloat64 value)
{
int function = pasynUser->reason;
asynStatus status = asynSuccess;
almAxis *pAxis = getAxis(pasynUser);
const char *paramName = "(unset)";
if (!pAxis)
return asynError;
/* Fetch the parameter string name for possible use in debugging */
getParamName(function, ¶mName);
/* Set the parameter and readback in the parameter library. This may be overwritten when we read back the
* status at the end, but that's OK */
status = setDoubleParam(pAxis->axisNo_, function, value);
#if DEBUG
printf("Param %s value %g\n", paramName, value);
#endif
if (function == param_input_threshold_[0]) {
status = setInputThreshold(0, value);
} else if (function == param_input_threshold_[1]) {
status = setInputThreshold(1, value);
} else if (function == param_input_threshold_[2]) {
status = setInputThreshold(2, value);
} else if (function == param_input_threshold_[3]) {
status = setInputThreshold(3, value);
} else if (function == param_limit_thresh_[ALM_LIM_LOW]) {
status = pAxis->setLowLimitThreshold(value);
} else if (function == param_limit_thresh_[ALM_LIM_HIGH]) {
status = pAxis->setHighLimitThreshold(value);
} else if (function == param_hold_i_) {
status = pAxis->setHoldCurrent(value);
} else if (function == param_move_i_) {
status = pAxis->setMoveCurrent(value);
} else {
/* Call base class method */
status = asynMotorController::writeFloat64(pasynUser, value);
}
/* Do callbacks so higher layers see any changes */
callParamCallbacks(pAxis->axisNo_);
if (status)
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s:%s: error, status=%d function=%s (%d), value=%f\n",
driverName, __func__, status, paramName, function, value);
else
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s:%s: function=%s (%d), value=%f\n",
driverName, __func__, paramName, function, value);
return status;
}
/** Called when asyn clients call pasynUInt32Digital->write().
* Extracts the function and axis number from pasynUser.
* Sets the value in the parameter library.
*
* Calls any registered callbacks for this pasynUser->reason and address.
* \param[in] pasynUser asynUser structure that encodes the reason and address.
* \param[in] value Value to write. */
asynStatus almController::writeUInt32Digital(asynUser *pasynUser, epicsUInt32 value, epicsUInt32 mask)
{
int function = pasynUser->reason;
asynStatus status = asynSuccess;
almAxis *pAxis = getAxis(pasynUser);
const char *paramName = "(unset)";
if (!pAxis)
return asynError;
/* Fetch the parameter string name for possible use in debugging */
getParamName(function, ¶mName);
/* Set the parameter and readback in the parameter library. This may be overwritten when we read back the
* status at the end, but that's OK */
status = setUIntDigitalParam(pAxis->axisNo_, function, value, mask);
#if DEBUG
printf("%s:%s: mask=%x function=%s (%d), value=%d\n",
driverName, __func__, mask, paramName, function, value);
#endif
if (param_mode_) {
status = setMode(value);
} else if (param_sp_mode_) {
status = setSpecialMode(value);
} else {
/* Call base class method */
status = asynMotorController::writeUInt32Digital(pasynUser, value, mask);
}
/* Do callbacks so higher layers see any changes */
callParamCallbacks(pAxis->axisNo_);
if (status)
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s:%s: error, status=%d function=%s (%d), value=%d\n",
driverName, __func__, status, paramName, function, value);
else
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s:%s: function=%s (%d), value=%d\n",
driverName, __func__, paramName, function, value);
return status;
}
/** Called when asyn clients call pasynOctet->write().
* Extracts the function and axis number from pasynUser.
* Sets the value in the parameter library.
*
* \param[in] pasynUser asynUser structure that encodes the reason and address.
* \param[in] value Value to write. */
asynStatus almController::writeOctet(asynUser *pasynUser, const char *value,
size_t nChars, size_t *nActual)
{
int addr=0;
int function = pasynUser->reason;
asynStatus status = asynSuccess;
const char *paramName = "(unset)";
bool handled=false;
int i;
/* Fetch the parameter string name for possible use in debugging */
getParamName(function, ¶mName);
#if DEBUG
printf("%s:%s: function=%s (%d), value=%s\n",
driverName, __func__, paramName, function, value);
#endif
status = getAddress(pasynUser, &addr);
if (status != asynSuccess)
return status;
/* Set the parameter in the parameter library. */
status = (asynStatus)setStringParam(addr, function, (char *)value);
*nActual = nChars;
for (i=0; i < ALM_PROG_COUNT; i++) {
if (function == param_prog_[i]) {
status = writeProgram(i, value);
handled = true;
}
}
if (!handled) {
if (param_prog_write_) {
getIntegerParam(param_prog_idx_, &i);
asynPrint(pasynUser, ASYN_TRACE_FLOW,
"%s:%s: write program %d value=%s\n",
driverName, __func__, i, value);
if (0 <= i && i < ALM_PROG_COUNT) {
setStringParam(addr, param_prog_[i], (char *)value);
status = writeProgram(i, value);
}
} else {
return asynPortDriver::writeOctet(pasynUser, value, nChars, nActual);
}
}
if (status)
epicsSnprintf(pasynUser->errorMessage, pasynUser->errorMessageSize,
"%s:%s: status=%d, function=%d, value=%s",
driverName, __func__, status, function, value);
else
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s:%s: function=%d, value=%s\n",
driverName, __func__, function, value);
return status;
}
/** Called when asyn clients call pasynInt32->write().
* Extracts the function and axis number from pasynUser.
* Sets the value in the parameter library.
*
* \param[in] pasynUser asynUser structure that encodes the reason and address.
* \param[in] value Value to write. */
asynStatus almController::writeInt32(asynUser *pasynUser, epicsInt32 value)
{
int function = pasynUser->reason;
asynStatus status = asynSuccess;
almAxis *pAxis = getAxis(pasynUser);
const char *paramName = "(unset)";
if (!pAxis)
return asynError;
/* Fetch the parameter string name for possible use in debugging */
getParamName(function, ¶mName);
#if DEBUG
printf("%s:%s: function=%s (%d), value=%d\n",
driverName, __func__, paramName, function, value);
#endif
/* Set the parameter and readback in the parameter library. This may be overwritten when we read back the
* status at the end, but that's OK */
status = setIntegerParam(pAxis->axisNo_, function, value);
if (function == param_kill_all_) {
terminateCommand();
} else if (function == param_read_adc_) {
status = readADC();
} else if (function == param_read_inp_) {
status = queryInputs();
} else if (function == param_read_thresh_) {
status = getInputThresholds();
} else if (function == param_read_limit_thresh_) {
status = getLimitThresholds();
} else if (function == param_prog_run_) {
status = runProgram(value);
} else if (function == param_reset_) {
status = resetDevice();
} else if (function == param_driver1_power_) {
status = driverPower(1, value);
} else if (function == param_driver2_power_) {
status = driverPower(2, value);
} else if (function == param_switch_debounce_) {
status = setSwitchDebounce(value);
} else if (function == param_daughter_current_) {
status = daughterCurrent(value);
} else if (function == param_daughter_cur_flow_) {
status = daughterCurrentFlow((bool)value);
} else if (function == param_pot_offset_) {
status = setPotOffset(value);
} else if (function == param_pot_mul_) {
status = setPotMul(value);
} else if (function == param_pot_deadband_) {
status = setPotDeadband(value);
} else if (function == param_enc_outer_db_) {
status = setEncoderOuterDeadband(value);
} else if (function == param_enc_inner_db_) {
status = setEncoderInnerDeadband(value);
} else if (function == param_enc_ratio_) {
status = setEncoderRatio(value);
} else if (function == param_overload_timeout_) {
status = setOverloadTimeout(value);
} else if (function == param_int_period_) {
status = setIntegrationPeriod(value);
} else if (function == param_recovery_runs_) {
status = setRecoveryScriptRuns(value);
} else if (function == param_microsteps_) {
status = pAxis->setMicrosteps(value);
} else if (function == param_microstep_tweak_) {
status = pAxis->setMicrostepTweak(value);
} else if (function == param_invert_input_[0]) {
status = invertInputs(0, value);
} else if (function == param_invert_input_[1]) {
status = invertInputs(1, value);
} else if (function == param_invert_input_[2]) {
status = invertInputs(2, value);
} else if (function == param_invert_input_[3]) {
status = invertInputs(3, value);
} else if (function == param_limit_invert_) {
status = pAxis->setLimitPolarity((value == 1));
} else {
/* Call base class method */
status = asynMotorController::writeInt32(pasynUser, value);
}
/* Do callbacks so higher layers see any changes */
callParamCallbacks(pAxis->axisNo_);
if (status)
asynPrint(pasynUser, ASYN_TRACE_ERROR,
"%s:%s: error, status=%d function=%s (%d), value=%d\n",
driverName, __func__, status, paramName, function, value);
else
asynPrint(pasynUser, ASYN_TRACEIO_DRIVER,
"%s:%s: function=%s (%d), value=%d\n",
driverName, __func__, paramName, function, value);
return status;
}
asynStatus almController::queryParameter(int axis, const char *operand, almResponsePacket &response) {
almCommandPacket command;
initCommandPacket(command);
command.select_axis(axis);
if (operand[0] == '&') {
command.append(operand[0]);
} else {
command.append("?%s", operand);
}
//command.dump();
asynStatus ret = writeRead(response, command);
return ret;
}
asynStatus almController::terminateCommand() {
almCommandPacket command;
initCommandPacket(command);
command.terminate();
asynStatus ret = runWrite(command);
if (ret == asynError) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
"%s:%s: controller terminate failed\n",
driverName, __func__);
}
return ret;
}
asynStatus almController::writeReadInt(int &ret, almCommandPacket &command) {
almResponsePacket response;
asynStatus status = writeRead(response, command);
if (status != asynSuccess) {
return status;
}
ret = response.as_int();
return asynSuccess;
}
asynStatus almController::writeRead(almResponsePacket &input, almCommandPacket *command, int retries) {
if (!command)
return asynError;
return writeRead(input, *command, retries);
}
asynStatus almController::writeRead(almResponsePacket &input, almCommandPacket &command, int retries) {
size_t nwrite;
size_t nread;
asynStatus status;
int eomReason;
char buf[ALM_STRING_LEN];
if (!command.finish()) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
"%s failed: finish packet failed\n",
__func__);
return asynError;
}
input.invalidate();
lock();
command.dump(pasynUser_, ASYN_TRACEIO_DRIVER);
status = pasynOctetSyncIO->writeRead(pasynUser_,
(const char*)command.get_buffer(), command.length(),
buf, ALM_STRING_LEN,
timeout_, &nwrite, &nread, &eomReason);
unlock();
if (nread > 0) {
input.received((const byte*)buf, nread);
if (nread > 0) {
input.dump(pasynUser_, ASYN_TRACEIO_DEVICE);
}
}
if (!input.is_valid()) {
if (retries > 0) {
asynPrint(pasynUser_, ASYN_TRACEIO_DRIVER,
"%s:%s: retransmit\n",
driverName, __func__);
command.set_repeat();
return writeRead(input, command, retries - 1);
}
asynPrint(pasynUser_, ASYN_TRACEIO_DRIVER|ASYN_TRACE_ERROR,
"%s failed: no confirmation from device (eomReason=%d) (nread=%d)\n",
__func__, eomReason, (int)nread);
status = asynError;
} else {
if (input.get_status() != ALM_NO_ERROR) {
almStatus code = input.get_status();
asynPrint(pasynUser_, ASYN_TRACEIO_DRIVER|ASYN_TRACE_ERROR,
"%s failed (AllMotion code=%d [%s] eomReason=%d nread=%d)\n",
__func__, code, get_allmotion_error_string(code),
eomReason, (int)nread);
setStringParam(param_error_, get_allmotion_error_string(code));
status = asynError;
} else {
status = asynSuccess;
asynPrint(pasynUser_, ASYN_TRACEIO_DRIVER,
"%s:%s: %s OK\n",
driverName, __func__, command.get_buffer());
}
}
if (input.is_valid()) {
input.dump(pasynUser_, ASYN_TRACEIO_DEVICE);
response_code_ = input.get_status();
ready_ = input.is_ready();
} else {
asynPrint(pasynUser_, ASYN_TRACEIO_DEVICE|ASYN_TRACE_ERROR,
"Invalid response");
setStringParam(param_error_, "Invalid response");
input.dump(pasynUser_, ASYN_TRACEIO_DEVICE|ASYN_TRACE_ERROR);
}
return status;
}
asynStatus almController::write(almCommandPacket &command, int retries) {
almResponsePacket response;
return writeRead(response, command, retries);
}
asynStatus almController::write(almCommandPacket *command, int retries) {
almResponsePacket response;
if (!command)
return asynError;
return writeRead(response, command, retries);
}
almCommandPacket *almController::getCommandPacket() {
return new almCommandPacket(address_);
}
void almController::initCommandPacket(almCommandPacket &packet) {
packet.clear();
packet.start(address_);
}
double adc_to_volts(int value) {
// 0 to 16368 -> 0.0 to 3.3V
return 3.3 * ((double)value / 16368.0);
}
unsigned int volts_to_adc(double volts) {
// 0 to 16368 <- 0.0 to 3.3V
return (unsigned int)((volts / 3.3) * 16368.0);
}
asynStatus almController::readADC() {
almResponsePacket response;
almCommandPacket command;
initCommandPacket(command);
command.read_adc();
asynStatus status = writeRead(response, command);
if (status == asynSuccess) {
int adc_int[ALM_INPUT_COUNT];
sscanf((const char*)response.get_buffer(), "%d,%d,%d,%d",
&adc_int[3], &adc_int[2], &adc_int[1], &adc_int[0]);
for (int i=0; i < ALM_INPUT_COUNT; i++) {
adc_[i] = adc_to_volts(adc_int[i]);
setDoubleParam(param_adc_[i], adc_[i]);
}
asynPrint(pasynUser_, ASYN_TRACE_FLOW,
"Read ADC: %gV %gV %gV %gV\n",
adc_[0], adc_[1], adc_[2], adc_[3]);
}
return status;
}
asynStatus almController::runWrite(almCommandPacket &command) {
command.run();
command.dump(pasynUser_, ASYN_TRACEIO_DRIVER);
asynStatus ret = write(command);
return ret;
}
asynStatus almController::writeProgram(int number, const char *program) {
if (strnchr(program, strlen(program), '/')) {
asynPrint(pasynUser_, ASYN_TRACE_ERROR,
"%s:%s: program contains slash: %s\n",
driverName, __func__, program);
return asynError;
}
almCommandPacket command;
initCommandPacket(command);
command.append("s%d", number);
command.append(program);
command.dump();
if (command.get_last_ch() == 'R')
return write(command);
else
return runWrite(command);
}
asynStatus almController::runProgram(int number) {
almCommandPacket command;
initCommandPacket(command);
command.append("e%d", number);
return runWrite(command);
}
asynStatus almController::setHomeFlagPolarity(bool polarity) {
almCommandPacket command;
initCommandPacket(command);
command.home_flag_polarity(polarity);
return runWrite(command);
}
asynStatus almController::invertInputs(unsigned int input, bool invert) {
int in[4];
for (int i=0; i < ALM_INPUT_COUNT; i++) {
getIntegerParam(param_invert_input_[i], &in[i]);
}
if (input >= ALM_INPUT_COUNT)
return asynError;
else
in[input] = invert;
almCommandPacket command;
initCommandPacket(command);
command.invert_inputs(in[0], in[1], in[2], in[3]);
command.dump();
return runWrite(command);
}
asynStatus almController::invertInputs(unsigned int mask) {
almCommandPacket command;
initCommandPacket(command);
command.invert_inputs(mask);
return runWrite(command);
}
asynStatus almController::resetDevice() {
almCommandPacket command;
initCommandPacket(command);
command.reset_processor();
return runWrite(command);
}
asynStatus almController::setSwitchDebounce(int periods) {
almCommandPacket command;
initCommandPacket(command);
command.switch_debounce(periods);
return runWrite(command);
}
asynStatus almController::driverPower(int driver, bool enabled) {
int enabled1, enabled2;
if (driver < 1 || driver > 2)
return asynError;
getIntegerParam(param_driver1_power_, &enabled1);
getIntegerParam(param_driver2_power_, &enabled2);
if (driver == 1)
enabled1 = enabled;
else
enabled2 = enabled;
almCommandPacket command;
initCommandPacket(command);
command.driver_power(enabled1, enabled2);
command.dump();
return runWrite(command);
}
asynStatus almController::daughterCurrent(unsigned int current) {
almCommandPacket command;
initCommandPacket(command);
command.daughter_current_flow(current);
return runWrite(command);
}
asynStatus almController::daughterCurrentFlow(bool direction) {
almCommandPacket command;
initCommandPacket(command);
command.daughter_current_flow(direction);
return runWrite(command);
}
asynStatus almController::setInputThreshold(unsigned int chan, double thresh) {
if (thresh < 0.0 || thresh > 3.3)
return asynError;
unsigned int raw_thresh = volts_to_adc(thresh);
almCommandPacket command;
initCommandPacket(command);
command.input_threshold(chan, raw_thresh);
command.dump();
asynStatus ret = runWrite(command);
getInputThresholds();
return ret;
}
asynStatus almController::getInputThresholds() {
almResponsePacket response;
int thresh[ALM_INPUT_COUNT];
if (queryControllerParam(ALM_QUERY_ADC_THRESHOLDS, response) == asynSuccess) {
//printf("Input thresholds %s\n", response.get_buffer());
sscanf((const char*)response.get_buffer(), "%d,%d,%d,%d",
&thresh[3], &thresh[2], &thresh[1], &thresh[0]);
// 0 to 16368 -> 0.0 to 3.3V
for (int i=0; i < ALM_INPUT_COUNT; i++) {
thresholds_[i] = adc_to_volts(thresh[i]);
setDoubleParam(param_input_threshold_[i], thresholds_[i]);
}
return asynSuccess;
}
return asynError;
}
asynStatus almController::getLimitThresholds() {
almResponsePacket response;
int thresh[2];
int n_read;
almAxis *axis;
if (queryControllerParam(ALM_QUERY_LIMIT_THRESHOLDS, response) == asynSuccess) {
// Limit thresholds:
// 12, 11, 22, 21, 32, 31, 42, 41
//
const char *buf = (const char*)response.get_buffer();
printf("Limit thresholds %s\n", response.get_buffer());
for (int ax=0; ax < ALM_AXES; ax++) {
sscanf(buf, ((ax != ALM_AXES-1) ? "%d,%d,%n" : "%d,%d%n"),
&thresh[0], &thresh[1], &n_read);
buf = &buf[n_read];
axis = getAxis(ax);
if (!axis) {
continue;
}
for (int i=0; i < 2; i++) {
axis->limit_threshold_[i] = adc_to_volts(thresh[i]);
setDoubleParam(ax, param_input_threshold_[i], axis->limit_threshold_[i]);
}
}
return asynSuccess;
}
return asynError;
}
asynStatus almController::setPotOffset(unsigned int offset) {
almCommandPacket command;
initCommandPacket(command);
command.pot_offset(offset);
return runWrite(command);
}
asynStatus almController::setPotMul(unsigned int mul) {
almCommandPacket command;
initCommandPacket(command);
command.pot_mul(mul);
return runWrite(command);
}
asynStatus almController::setPotDeadband(unsigned int deadband) {
almCommandPacket command;
initCommandPacket(command);
command.pot_deadband(deadband);
return runWrite(command);
}
asynStatus almController::queryInputs() {
almResponsePacket response;
// TODO: not sure why, but /1?4 and /1?a4 return different results
// (with the same input) for sw1/2 and opto1/2
if (queryControllerParam(ALM_QUERY_INPUTS, response) == asynSuccess) {
int ret = response.as_int();
setIntegerParam(param_inp_sw1_, (ret & ALM_INP_SW1) != 0);
setIntegerParam(param_inp_sw2_, (ret & ALM_INP_SW2) != 0);
setIntegerParam(param_inp_opto1_, (ret & ALM_INP_OPTO1) != 0);
setIntegerParam(param_inp_opto2_, (ret & ALM_INP_OPTO2) != 0);
}
if (queryControllerParam(ALM_QUERY_ALL_INPUTS, response) == asynSuccess) {
int ret = response.as_int();
//setIntegerParam(param_inp_sw1_, (ret & ALM_INP_SW1) != 0);
//setIntegerParam(param_inp_sw2_, (ret & ALM_INP_SW2) != 0);
//setIntegerParam(param_inp_opto1_, (ret & ALM_INP_OPTO1) != 0);
//setIntegerParam(param_inp_opto2_, (ret & ALM_INP_OPTO2) != 0);
setIntegerParam(param_inp_cha_, (ret & ALM_INP_ENC_CHA) != 0);
setIntegerParam(param_inp_chb_, (ret & ALM_INP_ENC_CHB) != 0);
setIntegerParam(param_inp_idx_, (ret & ALM_INP_ENC_IDX) != 0);
return asynSuccess;
}
return asynError;
}
asynStatus almController::queryVelocity() {
almResponsePacket response;
if (queryControllerParam(ALM_QUERY_VELOCITY, response) == asynSuccess) {
int ret = response.as_int();
velocities_[0] = ret;
for (int i=1; i < ALM_AXES; i++)
velocities_[i] = 0;
return asynSuccess;
}
return asynError;
}
asynStatus almController::queryFirmware() {
almResponsePacket response;
if (queryControllerParam(ALM_QUERY_FIRMWARE, response) == asynSuccess) {
printf("Firmware version: %s\n", response.get_buffer());
setStringParam(param_firmware_, (const char*)response.get_buffer());
return asynSuccess;
}
return asynError;
}
asynStatus almController::eraseEEPROM() {
almCommandPacket command;
initCommandPacket(command);
command.erase_eeprom();
return runWrite(command);
}
asynStatus almController::setEncoderOuterDeadband(unsigned int counts) {
almCommandPacket command;
initCommandPacket(command);
command.set_encoder_outer_deadband(counts);
return runWrite(command);
}
asynStatus almController::setEncoderInnerDeadband(unsigned int counts) {
almCommandPacket command;
initCommandPacket(command);
command.set_encoder_inner_deadband(counts);
return runWrite(command);
}
asynStatus almController::setEncoderRatio(unsigned int ticks_per_ustep) {
almCommandPacket command;
initCommandPacket(command);
command.set_encoder_ratio(ticks_per_ustep);
return runWrite(command);
}
asynStatus almController::setOverloadTimeout(unsigned int moves) {
almCommandPacket command;
initCommandPacket(command);
command.set_overload_timeout(moves);
return runWrite(command);
}
asynStatus almController::setIntegrationPeriod(unsigned int pd) {
almCommandPacket command;
initCommandPacket(command);
command.set_integration_period(pd);
return runWrite(command);
}
asynStatus almController::setRecoveryScriptRuns(unsigned int runs) {
almCommandPacket command;
initCommandPacket(command);
command.set_recovery_script_runs(runs);
return runWrite(command);
}
asynStatus almController::setMode(unsigned int mode) {
almCommandPacket command;
initCommandPacket(command);
command.set_mode(mode);
return runWrite(command);
}
asynStatus almController::setSpecialMode(unsigned int mode) {
almCommandPacket command;
initCommandPacket(command);
command.set_special_mode(mode);
return runWrite(command);
}
int almController::ampsToPercent(double amps) {
double max_amps;
getDoubleParam(param_max_amps_, &max_amps);
if (max_amps <= 0.0) {
max_amps = 2.0;
}
if (amps < 0.0) {
amps = 0.0;
} else if (amps > max_amps) {
amps = max_amps;
}
return (int)((amps / max_amps) * 100.0);
}
- Replies:
- RE: multiple USB devices in Asyn Mark Rivers via Tech-talk
- References:
- multiple USB devices in Asyn Siddons, David via Tech-talk
- RE: multiple USB devices in Asyn Mark Rivers via Tech-talk
- Navigate by Date:
- Prev:
RE: multiple USB devices in Asyn Mark Rivers via Tech-talk
- Next:
RE: multiple USB devices in Asyn Mark Rivers via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024
- Navigate by Thread:
- Prev:
RE: multiple USB devices in Asyn Mark Rivers via Tech-talk
- Next:
RE: multiple USB devices in Asyn Mark Rivers via Tech-talk
- Index:
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
<2020>
2021
2022
2023
2024
|