diff --git a/.gitignore b/.gitignore index 8aea051..5eff142 100644 --- a/.gitignore +++ b/.gitignore @@ -16,4 +16,5 @@ envPaths dllPath.bat auto_settings.sav* auto_positions.sav* +RELEASE.local diff --git a/iocBoot/iocTest/fc17_modicon.cmd b/iocBoot/iocTest/fc17_modicon.cmd new file mode 100755 index 0000000..bda2da5 --- /dev/null +++ b/iocBoot/iocTest/fc17_modicon.cmd @@ -0,0 +1,51 @@ +#!../../bin/linux-x86_64/modbusApp + +# fc17_modicon.cmd + + +< envPaths + +dbLoadDatabase("../../dbd/modbusApp.dbd") +modbusApp_registerRecordDeviceDriver(pdbbase) + +# Use the following commands for TCP/IP +#drvAsynIPPortConfigure(const char *portName, +# const char *hostInfo, +# unsigned int priority, +# int noAutoConnect, +# int noProcessEos); +drvAsynIPPortConfigure("Modicon984","192.168.1.52:4001",0,0,0) +#modbusInterposeConfig(const char *portName, +# modbusLinkType linkType, +# int timeoutMsec, +# int writeDelayMsec) +modbusInterposeConfig("Modicon984",1,500,0) + +#drvModbusAsynConfigure(portName, +# tcpPortName, +# slaveAddress, +# modbusFunction, +# modbusStartAddress, +# modbusLength, +# dataType, +# pollMsec, +# plcType); +# modbusStartAddress=0 as it doesn't matter in function 17 +# modbusLength is device-specific and equal to number of bytes in response of function 17 +# Modicon-984 provides 9 bytes in response +drvModbusAsynConfigure("Mod984_slaveID","Modicon984",32,17,0,9,0,1000,"Modicon") + +# Enable ASYN_TRACEIO_HEX on octet server +asynSetTraceIOMask("Modicon984",0,4) +# Enable ASYN_TRACE_ERROR and ASYN_TRACEIO_DRIVER on octet server +#asynSetTraceMask("Modicon984",0,9) + +# Enable ASYN_TRACEIO_HEX on modbus server +asynSetTraceIOMask("Mod984_slaveID",0,4) +# Enable ASYN_TRACE_ERROR, ASYN_TRACEIO_DEVICE, and ASYN_TRACEIO_DRIVER on modbus server +#asynSetTraceMask("Mod984_slaveID",0,11) + +dbLoadTemplate("fc17_modicon.substitutions") + +iocInit + diff --git a/iocBoot/iocTest/fc17_modicon.substitutions b/iocBoot/iocTest/fc17_modicon.substitutions new file mode 100644 index 0000000..cceeb0e --- /dev/null +++ b/iocBoot/iocTest/fc17_modicon.substitutions @@ -0,0 +1,18 @@ +# asyn record for the underlying asyn octet port +file "$(ASYN)/db/asynRecord.db" { pattern +{P, R, PORT, ADDR, IMAX, OMAX} +{Modicon984: OctetAsyn, Modicon984, 0, 80, 80} +} + +# read byte#1 out of 9 bytes from Modicon-984 response +file "../../db/longin.template" { pattern +{P, R, PORT, OFFSET, SCAN} +{Modicon984:, SlaveID_Byte1, Mod984_slaveID, 0, "I/O Intr"} +} + +# read byte#7 out of 9 bytes from Modicon-984 response +file "../../db/mbbiDirect.template" { pattern +{P, R, PORT, OFFSET, MASK, SCAN} +{Modicon984:, SlaveID_Byte7, Mod984_slaveID, 6, 0xFF, "I/O Intr"} +} + diff --git a/modbusApp/src/drvModbusAsyn.cpp b/modbusApp/src/drvModbusAsyn.cpp index 30387ad..781a8ad 100644 --- a/modbusApp/src/drvModbusAsyn.cpp +++ b/modbusApp/src/drvModbusAsyn.cpp @@ -231,6 +231,7 @@ drvModbusAsyn::drvModbusAsyn(const char *portName, const char *octetPortName, break; case MODBUS_READ_HOLDING_REGISTERS: case MODBUS_READ_INPUT_REGISTERS: + case MODBUS_REPORT_SLAVE_ID: case MODBUS_READ_INPUT_REGISTERS_F23: maxLength = MAX_READ_WORDS; needReadThread = 1; @@ -529,6 +530,7 @@ asynStatus drvModbusAsyn::readUInt32Digital(asynUser *pasynUser, epicsUInt32 *va case MODBUS_READ_DISCRETE_INPUTS: case MODBUS_READ_HOLDING_REGISTERS: case MODBUS_READ_INPUT_REGISTERS: + case MODBUS_REPORT_SLAVE_ID: case MODBUS_READ_INPUT_REGISTERS_F23: *value = data_[offset]; if ((mask != 0 ) && (mask != 0xFFFF)) *value &= mask; @@ -679,6 +681,7 @@ asynStatus drvModbusAsyn::readInt32 (asynUser *pasynUser, epicsInt32 *value) break; case MODBUS_READ_HOLDING_REGISTERS: case MODBUS_READ_INPUT_REGISTERS: + case MODBUS_REPORT_SLAVE_ID: case MODBUS_READ_INPUT_REGISTERS_F23: status = readPlcInt32(dataType, offset, value, &bufferLen); if (status != asynSuccess) return status; @@ -1814,7 +1817,16 @@ asynStatus drvModbusAsyn::doModbusIO(int slave, int function, int start, requestSize = sizeof(modbusReadRequest); /* The -1 below is because the modbusReadResponse struct already has 1 byte of data */ replySize = sizeof(modbusReadResponse) - 1 + len*2; - break; + break; + case MODBUS_REPORT_SLAVE_ID: + readReq = (modbusReadRequest *)modbusRequest_; + readReq->slave = slave; + readReq->fcode = function; + requestSize = 2; + //requestSize = sizeof(modbusReadRequest); + /* The -1 below is because the modbusReadResponse struct already has 1 byte of data */ + replySize = sizeof(modbusReadResponse) - 1 + len; + break; case MODBUS_READ_INPUT_REGISTERS_F23: readWriteMultipleReq = (modbusReadWriteMultipleRequest *)modbusRequest_; readWriteMultipleReq->slave = slave; @@ -2073,7 +2085,29 @@ asynStatus drvModbusAsyn::doModbusIO(int slave, int function, int start, "%s::%s port %s READ_REGISTERS\n", driverName, functionName, this->portName); break; - + case MODBUS_REPORT_SLAVE_ID: + readOK_++; + setIntegerParam(P_ReadOK, readOK_); + readResp = (modbusReadResponse *)modbusReply_; + nread = readResp->byteCount; + pCharIn = (epicsUInt8 *)&readResp->data; + /* Check to make sure we got back the expected number of words */ + + if ((int)nread != len) { + asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, + "%s::%s, port %s expected %d words, actually received %d\n", + driverName, functionName, this->portName, len, (int)nread); + status = asynError; + goto done; + } + for (i=0; i<(int)nread; i++) { + data[i] = pCharIn[i]; + } + asynPrintIO(pasynUserSelf, ASYN_TRACEIO_DRIVER, + (char *)data, nread, + "%s::%s port %s READ_REGISTERS\n", + driverName, functionName, this->portName); + break; /* We don't do anything with responses to writes for now. * Could add error checking. */ case MODBUS_WRITE_SINGLE_COIL: diff --git a/modbusApp/src/modbus.h b/modbusApp/src/modbus.h index afdcf1d..14d6440 100755 --- a/modbusApp/src/modbus.h +++ b/modbusApp/src/modbus.h @@ -19,6 +19,7 @@ #define MODBUS_WRITE_SINGLE_REGISTER 0x06 #define MODBUS_WRITE_MULTIPLE_COILS 0x0F #define MODBUS_WRITE_MULTIPLE_REGISTERS 0x10 +#define MODBUS_REPORT_SLAVE_ID 0x11 #define MODBUS_READ_WRITE_MULTIPLE_REGISTERS 0x17 #define MODBUS_EXCEPTION_FCN 0x80