static int ctx_set_byte_timeout(lua_State *L) { ctx_t *ctx = ctx_check(L, 1); int opt = luaL_checkinteger(L, 2); int opt2 = luaL_optinteger(L, 3, 0); #if LIBMODBUS_VERSION_CHECK(3,1,0) modbus_set_byte_timeout(ctx->modbus, opt, opt2); #else struct timeval t = { opt, opt2 }; modbus_set_byte_timeout(ctx->modbus, &t); #endif return 0; }
modbus_ctrl::modbus_ctrl(modbus_t* context) : next_write_time(0), shadow_registers() { this->context = context; if(context == NULL) { throw modbus_exception(); } //set timeout struct timeval timeout_end; struct timeval timeout_begin; modbus_get_byte_timeout(context, &timeout_end); timeout_end.tv_usec = TIMEOUT_END; modbus_set_byte_timeout(context, &timeout_end); modbus_get_response_timeout(context, &timeout_begin); timeout_begin.tv_usec = TIMEOUT_BEGIN; modbus_set_response_timeout(context, &timeout_begin); //connect if(modbus_connect(context) == -1) { throw modbus_exception(); } }
// Function for changing Modbus bytes timeout void ModbusClientV1::change_byte_timeout(int sec, int usec) { struct timeval t; modbus_get_byte_timeout(ctx, &t); printTimeTV("Initial byte timeout", &t); t.tv_sec = sec; t.tv_usec = usec; modbus_set_byte_timeout(ctx, &t); modbus_get_byte_timeout(ctx, &t); printTimeTV("New byte timeout", &t); }
void ModbusMaster::readRegisterList(QList<quint16> registerList) { QMap<quint16, ModbusResult> resultMap; quint32 success = 0; quint32 error = 0; /* Open port */ modbus_t * pCtx = openPort(_pSettingsModel->ipAddress(), _pSettingsModel->port()); if (pCtx) { /* Set modbus slave */ modbus_set_slave(pCtx, _pSettingsModel->slaveId()); // Disable byte time-out uint32_t sec = -1; uint32_t usec = 0; modbus_set_byte_timeout(pCtx, sec, usec); // Set response timeout sec = _pSettingsModel->timeout() / 1000; usec = (_pSettingsModel->timeout() % 1000) * 1000uL; modbus_set_response_timeout(pCtx, sec, usec); // Do optimized reads qint32 regIndex = 0; while (regIndex < registerList.size()) { quint32 count = 0; // get number of subsequent registers if ( ((registerList.size() - regIndex) > 1) && (_pSettingsModel->consecutiveMax() > 1) ) { bool bSubsequent; do { bSubsequent = false; // if next is current + 1, dan subsequent = true if (registerList.at(regIndex + count + 1) == registerList.at(regIndex + count) + 1) { bSubsequent = true; count++; } // Break loop when end of list if ((regIndex + count) >= ((uint)registerList.size() - 1)) { break; } // Limit number of register in 1 read if (count > (_pSettingsModel->consecutiveMax() - 1u - 1u)) { break; } } while(bSubsequent == true); } // At least one register count++; // Read registers QList<quint16> registerDataList; qint32 returnCode = readRegisters(pCtx, registerList.at(regIndex) - 40001, count, ®isterDataList); if (returnCode == 0) { success++; for (uint i = 0; i < count; i++) { const quint16 registerAddr = registerList.at(regIndex) + i; const ModbusResult result = ModbusResult(registerDataList[i], true); resultMap.insert(registerAddr, result); } } else { /* only split on specific modbus exception (invalid value and invalid address) */ if ( (returnCode == (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_ADDRESS)) || (returnCode == (MODBUS_ENOBASE + MODBUS_EXCEPTION_ILLEGAL_DATA_VALUE)) ) { /* Consecutive read failed */ if (count == 1) { /* Log error */ error++; const quint16 registerAddr = registerList.at(regIndex); const ModbusResult result = ModbusResult(0, false); resultMap.insert(registerAddr, result); } else { error++; /* More than one => read all separately */ for (quint32 i = 0; i < count; i++) { const quint16 registerAddr = registerList.at(regIndex + i); if (readRegisters(pCtx, registerAddr - 40001, 1, ®isterDataList) == 0) { success++; const ModbusResult result = ModbusResult(registerDataList[0], true); resultMap.insert(registerAddr, result); } else { /* Log error */ error++; const ModbusResult result = ModbusResult(0, false); resultMap.insert(registerAddr, result); } } } } else { error++; for (qint32 i = 0; i < registerList.size(); i++) { const quint16 registerAddr = registerList.at(i); const ModbusResult result = ModbusResult(0, false); resultMap.insert(registerAddr,result); } break; } } // Set register index to next register regIndex += count; } closePort(pCtx); /* Close port */ } else { error++; for (qint32 i = 0; i < registerList.size(); i++) { const quint16 registerAddr = registerList.at(i); const ModbusResult result = ModbusResult(0, false); resultMap.insert(registerAddr,result); } } _pGuiModel->setCommunicationStats(_pGuiModel->communicationSuccessCount() + success, _pGuiModel->communicationErrorCount() + error); emit modbusPollDone(resultMap); }
int settimeouts(void){ modbus_set_byte_timeout(ctx,TIMEOUTDURATION,0); modbus_set_response_timeout(ctx,TIMEOUTDURATION,0); return 1; }
bool RbCtrlIface::connectModbus( int retryCount/*=-1*/) { // >>>>> Simulation? if(mSimulActive) { ROS_WARN_STREAM( "ModBus replies are simulated!" ); ros::Duration(1).sleep(); // sleep for a second return true; } // <<<<< Simulation? if( !mModbus ) { ROS_FATAL_STREAM( "ModBus data structure not initialized!" ); return false; } // Closing to reset active connections //modbus_close( mModbus); if( modbus_connect( mModbus ) == -1 ) { ROS_FATAL_STREAM( "Modbus connection failed" ); mBoardConnected = false; return false; } int res=-1; // res = modbus_flush( mModbus ); ros::Duration(1).sleep(); // sleep for a second timeval new_timeout; new_timeout.tv_sec = 2; new_timeout.tv_usec = 0; modbus_set_response_timeout( mModbus, &new_timeout ); modbus_set_byte_timeout( mModbus, &new_timeout ); res = modbus_set_slave( mModbus, mBoardIdx ); if( res != 0 ) { ROS_FATAL_STREAM( "modbus_set_slave error -> " << modbus_strerror( errno ) ); modbus_flush( mModbus ); mBoardConnected = false; return false; } int tryCount=0; bool ok = false; mBoardConnected = true; while(1) { ROS_WARN_STREAM( "- testBoardConnection - Attempt: " << (tryCount+1) ); ok = testBoardConnection(); tryCount++; if( tryCount==retryCount || ok ) break; else ROS_WARN_STREAM( "Trying again..."); } if( !ok ) { ROS_FATAL_STREAM( "Error on modbus: " << modbus_strerror( errno ) ); mBoardConnected = false; return false; } return true; }
retCode get_tx_connection(const int this_mb_tx_num, int *ret_connected) { char *fnct_name = "get_tx_connection"; int ret; mb_tx_t *this_mb_tx; mb_link_t *this_mb_link; int this_mb_link_num; struct timeval timeout; if (this_mb_tx_num < 0 || this_mb_tx_num > gbl.tot_mb_tx) { ERR(gbl.init_dbg, "parameter out of range this_mb_tx_num[%d]", this_mb_tx_num); return retERR; } this_mb_tx = &gbl.mb_tx[this_mb_tx_num]; if (ret_connected == NULL) { ERR(this_mb_tx->cfg_debug, "NULL pointer"); return retERR; } this_mb_link_num = this_mb_tx->mb_link_num; if (this_mb_link_num < 0 || this_mb_link_num >= gbl.tot_mb_links) { ERR(this_mb_tx->cfg_debug, "parameter out of range this_mb_link_num[%d]", this_mb_link_num); return retERR; } this_mb_link = &gbl.mb_links[this_mb_link_num]; *ret_connected = 0; //defaults to not connected if (modbus_get_socket(this_mb_link->modbus) < 0) { ret = modbus_connect(this_mb_link->modbus); if (ret != 0 || modbus_get_socket(this_mb_link->modbus) < 0) { modbus_set_socket(this_mb_link->modbus, -1); //some times ret was < 0 and fd > 0 ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] cannot connect to link, ret[%d] fd[%d]", this_mb_tx_num, this_mb_tx->mb_link_num, ret, modbus_get_socket(this_mb_link->modbus)); return retOK; //not connected } DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] new connection -> fd[%d]", this_mb_tx_num, this_mb_tx->mb_link_num, modbus_get_socket(this_mb_link->modbus)); } else { DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] already connected to fd[%d]", this_mb_tx_num, this_mb_tx->mb_link_num, modbus_get_socket(this_mb_link->modbus)); } //set slave id according to each mb_tx ret = modbus_set_slave(this_mb_link->modbus, this_mb_tx->mb_tx_slave_id); if (ret != 0) { ERR(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] cannot set slave [%d]", this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_tx->mb_tx_slave_id); return retOK; //not connected } //set the low level mb_link debug according to each mb_tx modbus_set_debug(this_mb_link->modbus, this_mb_tx->protocol_debug); //set response and byte timeout according to each mb_tx timeout.tv_sec = this_mb_tx->mb_response_timeout_ms / 1000; timeout.tv_usec = (this_mb_tx->mb_response_timeout_ms % 1000) * 1000; #if (LIBMODBUS_VERSION_CHECK(3, 1, 2)) modbus_set_response_timeout(this_mb_link->modbus, timeout.tv_sec, timeout.tv_usec); #else modbus_set_response_timeout(this_mb_link->modbus, &timeout); #endif //DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] response timeout [%d] ([%d] [%d])", // this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_tx->mb_response_timeout_ms, // (int) timeout.tv_sec, (int) timeout.tv_usec); timeout.tv_sec = this_mb_tx->mb_byte_timeout_ms / 1000; timeout.tv_usec = (this_mb_tx->mb_byte_timeout_ms % 1000) * 1000; #if (LIBMODBUS_VERSION_CHECK(3, 1, 2)) modbus_set_byte_timeout(this_mb_link->modbus, timeout.tv_sec, timeout.tv_usec); #else modbus_set_byte_timeout(this_mb_link->modbus, &timeout); #endif //DBG(this_mb_tx->cfg_debug, "mb_tx_num[%d] mb_links[%d] byte timeout [%d] ([%d] [%d])", // this_mb_tx_num, this_mb_tx->mb_link_num, this_mb_tx->mb_byte_timeout_ms, // (int) timeout.tv_sec, (int) timeout.tv_usec); *ret_connected = 1; //is connected (fd >= 0) return retOK; }
/* * * MAIN process * */ int main(int argc, char* argv[]) { char serial_port[32] = SERIAL_PORT_PREFIX; int baud_rate; int num_slaves; int i, k; if ((argc < 6) || ((argc>6) && (argc<NUM_REG_PER_SLAVE+5))) { printf("Usage:\n\n"); printf(" Single slave (passthrough) mode:\n"); printf(" mbrtud <serial dev> <baudrate> <num_regs> <reg_offset> <slave addr>\n"); printf(" serial dev: name of the serial device used for connection to the Modbus converter (e.g. USB0 or S0)\n"); printf(" baudrate: baudrate used for serial connection\n"); printf(" num_regs: number of consecutive registers to read\n"); printf(" reg_offset: register address offset to add for slave request\n"); printf(" slave addr: address of Modbus slave device\n\n"); printf(" Multiple slave (register mapping) mode:\n"); printf(" mbrtud <serial dev> <baudrate> <num_regs> <reg 1> ... <reg %d> <slave addr> [<slave addr> ...]\n", NUM_REG_PER_SLAVE); printf(" serial dev: name of the serial device used for connection to the Modbus converter (e.g. USB0 or S0)\n"); printf(" baudrate: baudrate used for serial connection\n"); printf(" num_regs: number of consecutive registers to read\n"); printf(" reg x: register map to use for slave request\n"); printf(" slave addr: address of Modbus slave devices (up to %d)\n", MAX_SLAVES); return 0; } openlog("mbrtud", LOG_PID|LOG_CONS, LOG_USER); syslog(LOG_DAEMON | LOG_NOTICE, "Starting Modbus RTU daemon (version %s)\n", VERSION); /* Install signal handler for SIGTERM and SIGINT ("CTRL C") to be used to terminate */ signal(SIGTERM, doExit); signal(SIGINT, doExit); /* Get input parameters */ i=1; strcat(serial_port, argv[i++]); baud_rate = atoi(argv[i++]); num_regs = atoi(argv[i++]); if (argc == 6) { /* Single slave (passthrough) mode */ mode=MODE_SINGLESLAVE; reg_offset = atoi(argv[i++]); slave_addr_table[0] = atoi(argv[i++]); } else { /* Multiple slave (register mapping) mode */ mode=MODE_MULTISLAVE; for (k=0; (i<argc)&&(k<NUM_REG_PER_SLAVE); i++, k++) custom_reg_table[k] = atoi(argv[i]); memset(slave_addr_table, 0, sizeof(slave_addr_table)); for (k=0; (i<argc)&&(k<MAX_SLAVES); i++, k++) slave_addr_table[k] = atoi(argv[i]); num_slaves = k; } /* Init the Modbus RTU connection */ mb = modbus_new_rtu(serial_port, baud_rate, 'N', 8, 1); if (mb == NULL) { syslog(LOG_DAEMON | LOG_ERR, "Unable to create RTU485 context\n"); modbus_free(mb); return 1; } if (modbus_connect(mb) == -1) { syslog(LOG_DAEMON | LOG_ERR, "Connection failed: %s\n", modbus_strerror(errno)); return 2; } /* Set Modbus timeouts */ modbus_set_response_timeout(mb, 20, 0); modbus_set_byte_timeout(mb, 1, 0); /* Specific setting for direction control of the RS485 transceiver */ if (strstr(serial_port, "USB") == NULL) { /* Enable RS485 direction control via RTS line */ if (modbus_rtu_set_rts(mb, MODBUS_RTU_RTS_DOWN) == -1) { syslog(LOG_DAEMON | LOG_ERR, "Setting RTS mode failed: %s\n", modbus_strerror(errno)); modbus_free(mb); return 3; } /* Set RTS control delay (before and after transmission) */ if (DEFAULT_RTS_DELAY > 0) { if (modbus_rtu_set_rts_delay(mb, DEFAULT_RTS_DELAY) == -1) { syslog(LOG_DAEMON | LOG_ERR, "Setting RTS delay failed: %s\n", modbus_strerror(errno)); modbus_free(mb); return 4; } } syslog(LOG_DAEMON | LOG_NOTICE, "using direction control via RTS line"); } //modbus_set_debug(mb, TRUE); syslog(LOG_DAEMON | LOG_NOTICE, "Using Modbus connection on serial port %s at %dbaud", serial_port, baud_rate); if (mode == MODE_SINGLESLAVE) { syslog(LOG_DAEMON | LOG_NOTICE, "Single slave mode - slave address: %d", slave_addr_table[0]); } else { syslog(LOG_DAEMON | LOG_NOTICE, "Multiple slave mode - register map for each slave:"); syslog(LOG_DAEMON | LOG_NOTICE, " Reg | Id "); syslog(LOG_DAEMON | LOG_NOTICE, " ---------"); for (i=0; i<NUM_REG_PER_SLAVE; i++) syslog(LOG_DAEMON | LOG_NOTICE, " %02d | %02d", i+1, custom_reg_table[i]); syslog(LOG_DAEMON | LOG_NOTICE, "List of slaves:"); for (i=0; i<num_slaves; i++) syslog(LOG_DAEMON | LOG_NOTICE, " slave %d: %d (regs[%d...%d])\n", i+1, slave_addr_table[i], i*NUM_REG_PER_SLAVE+1, i*NUM_REG_PER_SLAVE+NUM_REG_PER_SLAVE); } /* Start Modbus TCP server loop */ modbustcp_server(MODBUS_SLAVE_ADDRESS, // Modbus slave address read_register_handler, // Read register handler write_register_handler // Write register handler ); return 0; }