/** * Devuelve -1 si hay error. */ int MODBUSPuerto::leer (int cod, int inicio, int tam,char buffer[]){ log.debug("%s: %s codigo/inicio %d - %d",__FILE__, "Inicio funcion leer",cod, inicio); int count = 0 ; switch (cod){ case 0x01: if ((count = modbus_read_input_bits(ctx,inicio,tam, (unsigned char*) buffer)) == -1){ log.error("%s: %s %s",__FILE__, "Error leyendo modbuss", modbus_strerror(errno)); this->reabrir(); } break; case 0x02: log.warn("%s: %s",__FILE__, "Codigo modbus 0x02 no implementado"); break; case 0x03: if ((count = modbus_read_input_registers(ctx,inicio,tam, (unsigned short int*) buffer)) == -1){ log.error("%s: %s %s",__FILE__, "Error leyendo modbuss", modbus_strerror(errno)); if (this->reabrir()!=0) log.error("%s: %s %s",__FILE__, "Error reabriendo puerto", modbus_strerror(errno)); } break; case 0x04: if ((count = modbus_read_registers(ctx,inicio,tam, (unsigned short int*) buffer)) == -1){ log.error("%s: %s %s",__FILE__, "Error leyendo modbuss", modbus_strerror(errno)); if (this->reabrir()!=0) log.error("%s: %s %s",__FILE__, "Error reabriendo puerto", modbus_strerror(errno)); } break; } log.debug("%s: %s %d",__FILE__, "Fin funcion leer modbus, resultado:", count); return count; }
/** * @brief Help function. FC1, FC2 request handler * * @fc Function code 1 and 2 only. * @param handle Mbtcp handle. * @param req cJSON request object. * @return Modbus response string in JSON format. */ static char * mbtcp_read_bit_req(int fc, mbtcp_handle_s *handle, cJSON *req) { BEGIN(enable_syslog); int addr = json_get_int(req, "addr"); int len = json_get_int(req, "len"); int tid = json_get_int(req, "tid"); if (len > MODBUS_MAX_READ_BITS) // 2000 { return set_modbus_error_resp(tid, "Too many bits requested"); } else { uint8_t bits[len]; // memory reset for variable length array memset(bits, 0, len * sizeof(uint8_t)); int ret = 0; switch (fc) { case 1: ret = modbus_read_bits(handle->ctx, addr, len, bits); break; case 2: ret = modbus_read_input_bits(handle->ctx, addr, len, bits); break; default: return set_modbus_error_resp(tid, "Wrong function code"); } if (ret < 0) { return set_modbus_errno_resp(tid, handle, errno); } else { LOG(enable_syslog, "fc:%d, desired length: %d, read length:%d", fc, len, ret); // [todo]:remove; debug only for (int ii = 0; ii < ret; ii++) { LOG(enable_syslog, "[%d]=%d", ii, bits[ii]); } // uint8_t array return set_modbus_with_data_ok_resp(tid, cJSON_CreateUInt8Array(bits, len)); } } }
/* * This Function sends modbus request and returns the response * Arguments: * unsigned char * fn :- Modbus request array. 1st byte is function code, next 2 bytes is address of register * 4th 5th byte is no. of register. 6th 7th byte is data. Modbus response is sent back on * 6th and 7th byte * Return Value :- 0 : On successful * -1 : on error */ int MBSendRequest(unsigned char *fn) { uint16_t address,NIitem,*data,data1 ; int ret=0; address = *(fn+1); address = address<<8; // This is done so that data recieved is in big indian format. address = address | (*(fn+2)); //It should be converted to little indian format NIitem = *(fn+3); NIitem = NIitem<<8; NIitem = NIitem | *(fn+4); data1 = *(fn+5); data1 = data1<<8; data1 = data1 | *(fn+6); data = &data1; printf("Function code = %d \n",*fn); printf("register address = %x \n",address); printf("NIitem = %x \n",NIitem); printf("Data=%d\n",*data); switch(*fn) { case 1:ret = modbus_read_bits(ctx,address,NIitem,(uint8_t*) data); break; case 2:ret = modbus_read_input_bits(ctx,address,NIitem,(uint8_t*) data); break; case 3:ret = modbus_read_registers(ctx,address,NIitem,data); break; case 4:ret = modbus_read_input_registers(ctx,address,NIitem,data); break; case 5:ret = modbus_write_bit(ctx,address,*data); break; case 6:ret = modbus_write_register(ctx,address,*data); break; case 15:ret = modbus_write_bits(ctx,address,NIitem,(uint8_t*) data); break; case 16:ret = modbus_write_registers(ctx,address,NIitem,data); break; } *(fn+6)=((*data) >> 8)& 0x00ff; *(fn+5)= (*data) & 0x00ff; return ret; }
void ModBusTCP::ReadDiscreteInputs(quint16 slave, quint16 addr, quint16 size, quint8 *data) { quint16 repeat = NumberOfRepeat; while(repeat) { if (modbus_set_slave(ctx, slave) == -1) { if (--repeat == 0) { qDebug() << "Error set slave: " << errno; emit ModBusError(errno); return; } } else { repeat = 0; } } repeat = NumberOfRepeat; while(repeat) { if (modbus_read_input_bits(ctx, addr, size, data) == -1) { if (--repeat == 0) { qDebug() << "Error read DiscreteInputs: " << errno; emit ModBusError(errno); return; } } else { repeat = 0; } } qDebug() << "Read OK" << repeat; emit ModBusOK(); }
static int _ctx_read_bits(lua_State *L, bool input) { ctx_t *ctx = ctx_check(L, 1); int addr = luaL_checknumber(L, 2); int count = luaL_checknumber(L, 3); int rcount = 0; int rc; if (count > MODBUS_MAX_READ_BITS) { return luaL_argerror(L, 3, "requested too many bits"); } uint8_t *buf = malloc(count * sizeof(uint8_t)); assert(buf); if (input) { rc = modbus_read_input_bits(ctx->modbus, addr, count, buf); } else { rc = modbus_read_bits(ctx->modbus, addr, count, buf); } if (rc == count) { lua_newtable(L); /* nota bene, lua style offsets! */ for (int i = 1; i <= rc; i++) { lua_pushnumber(L, i); /* TODO - push number or push bool? what's a better lua api? */ lua_pushnumber(L, buf[i-1]); lua_settable(L, -3); } rcount = 1; } else { rcount = libmodbus_rc_to_nil_error(L, rc, count); } free(buf); return rcount; }
/* Read values from modbus */ uint8_t read_modbus(modbus_t *ctx, uint8_t readOrWrite, uint16_t modbusRegister, GenDataType_t typeOfValue, MoBuRegType_t typeOfReg, uint8_t desiredBit, uint16_t* valueArray) { uint8_t noOfRegisters = 0; uint16_t modbusValueArray[2]; uint16_t modbusTmpValue; //used for bit values read from registers memset(modbusValueArray, 0x00, (sizeof(uint16_t) * 2)); if (readOrWrite > 0) { log_entry(APP_NAME, "invalid parameter in read_modbus: Only reading values supported"); printf("invalid parameter in read_modbus: Only reading values supported"); return -1; } switch (typeOfValue) { case bitCoil: case sint16: // read one address case uint16: //read one address noOfRegisters = 1; break; case sint32: //read 2 registers case uint32: case float32: noOfRegisters = 2; break; default: log_entry(APP_NAME, "MODBUSD; unknown dataType"); printf("MODBUSD; unknown dataType: %d", typeOfValue); } switch (typeOfReg) { case coil: if (0 == readOrWrite) { //read if (1 != modbus_read_bits(ctx, modbusRegister, 1, (uint8_t *) modbusValueArray)) { log_entry(APP_NAME, "MODBUSD: could not read coils"); printf("MODBUSD: could not read coils: %d, %s", modbusRegister, strerror(errno)); return -1; } } else { /* first read the whole unit16 value */ if (1 == modbus_read_bits(ctx, modbusRegister, 1, (uint8_t *) modbusValueArray)) { if (valueArray[0] == 0) { modbusTmpValue = 0; } else if (valueArray[0] == 1) { //setting bit to 1 modbusTmpValue = 1; } else { //toggle the bit if(0 == modbusValueArray[0]){ modbusTmpValue = 1; } else { modbusTmpValue = 0; } } if (1 != modbus_write_bit(ctx, modbusRegister, modbusTmpValue)) { return -1; } } } break; case discrete_input: if (0 == readOrWrite) { //read if (1 != modbus_read_input_bits(ctx, modbusRegister, noOfRegisters, (uint8_t *) &(modbusValueArray[0]))) { log_entry(APP_NAME, "MODBUSD: could not read input"); printf("MODBUSD: could not read input: %d, %s", modbusRegister, strerror(errno)); return -1; } } else { log_entry(APP_NAME, "MODBUSD: illegal operation -> unable to write on discrete input"); printf("MODBUSD: illegal operation -> unable to write on discrete input"); } break; case holding_register: if (0 == readOrWrite) { //read if (1 != modbus_read_registers(ctx, modbusRegister, noOfRegisters, &(modbusValueArray[0]))) { return -1; } } else { if (1 != modbus_write_registers(ctx, modbusRegister, noOfRegisters, &(valueArray[0]))) { return -1; } } break; case input_register: if (0 == readOrWrite) { //read if (1 != modbus_read_input_registers(ctx, modbusRegister, noOfRegisters, &(modbusValueArray[0]))) { log_entry(APP_NAME, "MODBUSD: could not read input registers"); printf("MODBUSD: could not read input registers: %d, %s", modbusRegister, strerror(errno)); return -1; } } else { log_entry(APP_NAME, "unable to write on input register"); printf("unable to write on input register"); } break; case holding_bit: if (0 == readOrWrite) { //read if (1 == modbus_read_registers(ctx, modbusRegister, noOfRegisters, &modbusTmpValue)) { modbusValueArray[0] = modbusTmpValue & (1 << desiredBit); } else { return -1; } } else { /* first read the whole unit16 value */ if (1 == modbus_read_registers(ctx, modbusRegister, noOfRegisters, &modbusTmpValue)) { if (valueArray[0] == 0) { //clearing a bit at postion desired bit modbusTmpValue &= ~(1 << desiredBit); } else if (valueArray[0] == 1) { //setting bit to 1 modbusTmpValue |= 1 << desiredBit; } else { //toggle the bit modbusTmpValue ^= 1 << desiredBit; } if (1 != modbus_write_registers(ctx, modbusRegister, noOfRegisters, &modbusTmpValue)) { return -1; } } else { return -1; } } break; case input_bit: if (0 == readOrWrite) { //read if (1 == modbus_read_input_registers(ctx, modbusRegister, noOfRegisters, &modbusTmpValue)) { modbusValueArray[0] = modbusTmpValue & (1 << desiredBit); } else { return -1; } } else { log_entry(APP_NAME, "MODBUSD; unable to write single bit for input register"); printf("MODBUSD; unable to write single bit for input register"); return -1; } break; default: log_entry(APP_NAME, "MODBUSD; unknown register type"); printf("MODBUSD; unknown register type %d", typeOfReg); } if (0 == readOrWrite) { //read valueArray[0] = modbusValueArray[0]; valueArray[1] = modbusValueArray[1]; } return 1; }
ssize_t MeterModbus::read(std::vector<Reading> &rds, size_t max_readings) { uint16_t in; double out; int rc; const struct addressparam *current_address; int read_count = 0; if(_reset_connection) { int success; print(log_info, "Resetting Connection to %s because of error", name().c_str(), _ip.c_str()); rc = open(); if(rc == SUCCESS) _reset_connection = false; else return 0; } current_address = _addressparams; unsigned char highest_digit, power; while((current_address->function_code != 0xFF) && (max_readings > read_count)) { getHighestDigit(current_address->address, &highest_digit, &power); switch(current_address->function_code){ case READ_HOLDING_REGISTERS: print(log_debug, "Accessing Holding Register %u", name().c_str(), current_address->address); rc = modbus_read_registers(_mb, current_address->address-4*(unsigned int)pow((double)10,(double)power)-1, 1, &in); break; case READ_INPUT_REGISTERS: print(log_debug, "Accessing Input Register %u", name().c_str(), current_address->address); rc = modbus_read_input_registers(_mb, current_address->address-3*(unsigned int)pow((double)10,(double)power)-1, 1, &in); break; case READ_COIL_STATUS: print(log_debug, "Accessing Coil Status register %u", name().c_str(), current_address->address); rc = modbus_read_bits(_mb, current_address->address, 1, (uint8_t *)&in); break; case READ_INPUT_STATUS: print(log_debug, "Accessing Input Status register %u", name().c_str(), current_address->address); rc = modbus_read_input_bits(_mb, current_address->address-2*(unsigned int)pow((double)10,(double)power)-1, 1, (uint8_t *)&in); break; } if (rc == -1 && errno != 112345680) { //Except Illegal Data Address print(log_error, "Unable to fetch data (FC: %u, ADR: %u): %s", name().c_str(), current_address->function_code, current_address->address, modbus_strerror(errno)); if(errno == 104 || errno == 32){ close(); _reset_connection = true; } return read_count; } if(rc == -1 && errno == 112345680){ print(log_error, "Unable to fetch data (FC: %u, ADR: %u): %s", name().c_str(), current_address->function_code, current_address->address, modbus_strerror(errno)); current_address++; continue; } print(log_debug, "Got %u via Modbus", "", in); // TODO ERRORS possible if wrong format string input from config file char *math_expression; asprintf(&math_expression, current_address->recalc_str, in); print(log_debug, "Calulating: %s --> %s", "", current_address->recalc_str, math_expression); out = parse_expression(math_expression); if(isnan(out)) { print(log_error, "Unable to use value read from address %u. Error calculating: %s", name().c_str(), current_address->address, math_expression); } else { rds[read_count].value(out); rds[read_count].time(); rds[read_count].identifier(new AddressIdentifier(current_address->address)); read_count++; } free(math_expression); current_address++; } return read_count; }
int main(int argc, char *argv[]) { uint8_t *tab_bits; uint8_t *tab_input_bits; uint16_t *tab_value_registers; uint16_t *tab_input_value_registers; modbus_t *ctx; int rc; float heaterTemp; float heaterSetPoint; char * heaterEnableState; char * heaterElementState; bool displayCnt = true; char * displayFlag; char * modbusClientIP = DEFAULT_CLIENT_IP; int modbusPort = DEFAULT_PORT; int modbusPollIntervalmSec = DEFAULT_POLL_INTERVAL_MSEC; int argcnt = 1; while(argc > argcnt) { if(strcmp(argv[argcnt], IP_ADDRESS_FLAG) == 0) { argcnt++; if(argcnt < argc) { modbusClientIP = argv[argcnt++]; } else { printf("Illegal command flags\n"); exit(1); } } else if(strcmp(argv[argcnt], IP_PORT_FLAG) == 0) { argcnt++; if(argcnt < argc) { sscanf(argv[argcnt++], "%i", &modbusPort); } else { printf("Illegal command flags\n"); exit(1); } } else if(strcmp(argv[argcnt], POLL_INTERVAL_FLAG) == 0) { argcnt++; if(argcnt < argc) { sscanf(argv[argcnt++], "%i", &modbusPollIntervalmSec); /* interpret command line argument as seconds. Convert to ms. */ modbusPollIntervalmSec *= 1000; } else { printf("Illegal command flags\n"); exit(1); } } else { printf("Illegal command flags\n"); exit(1); } } /* create modbus context structure */ ctx = modbus_new_tcp(modbusClientIP, modbusPort); if (ctx == NULL) { fprintf(stderr, "Unable to allocate libmodbus context\n"); return -1; } /* allocate room to hold water heater register data */ tab_bits = (uint8_t *)malloc(NUM_BIT_REG * sizeof(uint8_t)); memset(tab_bits, 0, NUM_BIT_REG * sizeof(uint8_t)); tab_input_bits = (uint8_t *)malloc(NUM_INPUT_BIT_REG * sizeof(uint8_t)); memset(tab_input_bits, 0, NUM_INPUT_BIT_REG * sizeof(uint8_t)); tab_value_registers = (uint16_t *)malloc(NUM_VALUE_REG * sizeof(uint16_t)); memset(tab_value_registers, 0, NUM_VALUE_REG * sizeof(uint16_t)); tab_input_value_registers = (uint16_t *)malloc(NUM_INPUT_VALUE_REG * sizeof(uint16_t)); memset(tab_input_value_registers, 0, NUM_INPUT_VALUE_REG * sizeof(uint16_t)); /* loop forever */ while(1) { if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); break; } rc = modbus_read_bits(ctx, HEATER_COIL_ENABLE, NUM_BIT_REG, tab_bits); if (rc != 1) { break; } rc = modbus_read_input_bits(ctx, HEATER_COIL_ENERGIZED, NUM_INPUT_BIT_REG, tab_input_bits); if (rc != 1) { break; } rc = modbus_read_input_registers(ctx, HEATER_WATER_TEMP_REG, NUM_INPUT_VALUE_REG, tab_input_value_registers); if (rc != 1) { break; } rc = modbus_read_registers(ctx, HEATER_WATER_TARGET_TEMP_REG, NUM_VALUE_REG, tab_value_registers); if (rc != 1) { break; } /* close the connection */ modbus_close(ctx); if(tab_bits[0]) { heaterEnableState = "Heater Enabled, "; } else { heaterEnableState = "Heater Disabled, "; } if(tab_input_bits[0]) { heaterElementState = "Heater Element On, "; } else { heaterElementState = "Heater Element Off, "; } heaterSetPoint = ((float)tab_value_registers[0]) / 10.0; heaterTemp = ((float)tab_input_value_registers[0]) / 10.0; if (displayCnt) { displayCnt = false; displayFlag = "+"; } else { displayCnt = true; displayFlag = "-"; } printf("Status(%s): %s%sSet Point: %5.1f, Temp: %5.1f\n", displayFlag, heaterEnableState, heaterElementState, heaterSetPoint, heaterTemp); memset(tab_input_value_registers, 0, NUM_INPUT_VALUE_REG * sizeof(uint16_t)); usleep(modbusPollIntervalmSec * 1000); } printf("Failed modbus read %d\n", rc); printf("Exiting due to read failure.\n"); /* Free the memory */ free(tab_bits); free(tab_input_bits); free(tab_value_registers); free(tab_input_value_registers); /* Close the connection */ modbus_close(ctx); modbus_free(ctx); return 0; }
int main( int argc, char **argv ) { int a, rc; int ec = 0; options_t options; modbus_t *ctx; uint8_t *tab_bit; uint16_t *tab_reg; if(argc > 1) { options_init(&options); for (a = 1; a < argc; a++) { options_execute(&options, argv[a], strlen(argv[a])+1); rc = options_finish(&options); DEBUG("argument: '%s' end state: %d\n",argv[a], rc); if (rc == -1) { options_err_disp(&options,argv[a]); ec = 1; goto exit; } } if(rc == 0) { fprintf(stderr, "Missing action argument\n"); ec = 1; goto exit; } if(options.action == _UNDEF) goto exit; // Options are valid options_dump(&options); ctx = modbus_init_con(&options); modbus_set_debug(ctx, options.debug); modbus_set_response_timeout(ctx, &options.timeout); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); ec = 1; goto destroy; } switch(options.action) { case _RC: case _RD: tab_bit = (uint8_t *) malloc(options.count * sizeof(uint8_t)); DBG_ASSERT(tab_bit != NULL, "Unable to allocate tab_bit!"); memset(tab_bit, 0, options.count * sizeof(uint8_t)); switch(options.action) { case _RC: rc = modbus_read_bits(ctx, options.address, options.count, tab_bit); break; case _RD: rc = modbus_read_input_bits(ctx, options.address, options.count, tab_bit); break; } if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); ec = 1; } else { display_8bit(&options, tab_bit); } free(tab_bit); break; case _RH: case _RI: tab_reg = (uint16_t *) malloc(options.count * sizeof(uint16_t)); DBG_ASSERT(tab_reg != NULL, "Unable to allocate tab_reg!"); switch(options.action) { case _RH: rc = modbus_read_registers(ctx, options.address, options.count, tab_reg); break; case _RI: rc = modbus_read_input_registers(ctx, options.address, options.count, tab_reg); break; } if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); ec = 1; } else { display_16bit(&options, tab_reg); } free(tab_reg); break; case _WC: if(options.count == 1) rc = modbus_write_bit(ctx, options.address, options.coil_values[0]); else { rc = modbus_write_bits(ctx, options.address, options.count, options.coil_values); } if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); ec = 1; } else { printf("Success\n"); } break; case _WH: if(options.count == 1) rc = modbus_write_register(ctx, options.address, options.reg_values[0]); else { rc = modbus_write_registers(ctx, options.address, options.count, options.reg_values); } if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); ec = 1; } else { printf("Success\n"); } break; default: DBG_ASSERT(0,"Unhandled action enum constant!"); } } else { options_help(); ec = 1; goto exit; } close: modbus_close(ctx); destroy: modbus_free(ctx); exit: return ec; }
/****************************************************************************** * * * Function: zbx_modbus_read_registers * * * * Purpose: a main entry point for processing of an item * * * * Parameters: request - structure that contains item key and parameters * * request->key - item key without parameters * * request->nparam - number of parameters * * request->timeout - processing should not take longer than * * this number of seconds * * request->params[N-1] - pointers to item key parameters * * * * result - structure that will contain result * * * * Return value: SYSINFO_RET_FAIL - function failed, item will be marked * * as not supported by zabbix * * SYSINFO_RET_OK - success * * * * Comment: get_rparam(request, N-1) can be used to get a pointer to the Nth * * parameter starting from 0 (first parameter). Make sure it exists * * by checking value of request->nparam. * * * ******************************************************************************/ int zbx_modbus_read_registers(AGENT_REQUEST *request, AGENT_RESULT *result) { char *param1, *param2,*param3,*param4,*param5,*param6,*param7; if (request->nparam <4) //check if mandatory params are provided { SET_MSG_RESULT(result, strdup("Invalid number of parameters.")); return SYSINFO_RET_FAIL; } param1 = get_rparam(request, 0); if(param_is_empty(param1)) { SET_MSG_RESULT(result, strdup("No connection address provided.")); return SYSINFO_RET_FAIL; } param2 = get_rparam(request, 1); if(param_is_empty(param2)) { SET_MSG_RESULT(result, strdup("No slave id provided.")); return SYSINFO_RET_FAIL; } param3 = get_rparam(request, 2); if(param_is_empty(param3)) { SET_MSG_RESULT(result, strdup("No register to read provided.")); return SYSINFO_RET_FAIL; } param4 = get_rparam(request, 3); if(param_is_empty(param4)) { SET_MSG_RESULT(result, strdup("No Modbus function provided! Please provide either 1,2,3,4.")); return SYSINFO_RET_FAIL; } modbus_t *ctx; int lock_required; create_modbus_context(param1,&ctx,&lock_required); if (ctx == NULL) { SET_MSG_RESULT(result, strdup("Unable to create the libmodbus context")); modbus_free(ctx); return SYSINFO_RET_FAIL; } //<slave_id> set slave id char *endptr; errno = 0; int slave_id = strtol(param2,&endptr, 0); if (errno!=0 || *endptr != '\0') { SET_MSG_RESULT(result, strdup("Check slaveid parameter")); modbus_free(ctx); return SYSINFO_RET_FAIL; } modbus_set_slave(ctx, slave_id); //<reg> set register to start from errno = 0; int reg_start = strtol(param3,&endptr, 0); if (errno!=0 || *endptr != '\0') { SET_MSG_RESULT(result, strdup("Check register to read")); modbus_free(ctx); return SYSINFO_RET_FAIL; } //set function to use errno = 0; int function = strtol(param4,&endptr, 0); if (errno!=0 || *endptr != '\0') { SET_MSG_RESULT(result, strdup("Check function (1,2,3,4) used")); modbus_free(ctx); return SYSINFO_RET_FAIL; } char datatype; int end = MODBUS_16BIT_LE; //<endianness> endianness LE(0) BE(1) default LE if (request->nparam > 4) { //optional params provided param5 = get_rparam(request, 4); //datatype if(!validate_datatype_param(param5)) { SET_MSG_RESULT(result, strdup("Check datatype provided.")); modbus_free(ctx); return SYSINFO_RET_FAIL; } datatype = *param5; // set datatype param6 = get_rparam(request, 5); //16 endiannes if(param6) { //endianness to use errno = 0; end = strtol(param6,&endptr, 0); if ( (end != MODBUS_16BIT_LE && end != MODBUS_16BIT_BE) || (errno!=0 || *endptr != '\0') ) { SET_MSG_RESULT(result, strdup("Check endiannes used")); modbus_free(ctx); return SYSINFO_RET_FAIL; } } param7 = get_rparam(request, 6); //PDU if(param7) {//PDU <first reg> check //int first_reg=atoi(param7); errno = 0; int first_reg = strtol(param7,&endptr, 0); if ( (first_reg != MODBUS_PROTOCOL_ADDRESS_1 && first_reg != MODBUS_PDU_ADDRESS_0) || (errno!=0 || *endptr != '\0') ) { SET_MSG_RESULT(result, strdup("Check addressing scheme(PDU,PROTOCOL) used")); modbus_free(ctx); return SYSINFO_RET_FAIL; } if (first_reg == MODBUS_PROTOCOL_ADDRESS_1){ reg_start=reg_start-1; } } } else {//no datatype set, place defaults if (function==MODBUS_READ_COIL_1 || function == MODBUS_READ_DINPUTS_2) { datatype = MODBUS_BIT;//default } if (function==MODBUS_READ_H_REGISTERS_3 || function == MODBUS_READ_I_REGISTERS_4) { datatype = MODBUS_INTEGER ;//default } } /* 3.0.3 struct timeval response_timeout ; response_timeout.tv_sec = 0; response_timeout.tv_usec = 0; modbus_set_response_timeout(ctx, &response_timeout); */ //modbus_set_response_timeout(ctx, 10, 0); //read part uint16_t tab_reg[64];//temp vars uint8_t tab_reg_bits[64]; int regs_to_read = 1; if (datatype == MODBUS_FLOAT || datatype == MODBUS_LONG) { regs_to_read=2;} if (lock_required == 1 ) LOCK_SERIAL_PORT; if (modbus_connect(ctx) == -1) { SET_MSG_RESULT(result, strdup(modbus_strerror(errno))); modbus_free(ctx); if (lock_required == 1 ) UNLOCK_SERIAL_PORT; return SYSINFO_RET_FAIL; } int rc;//modbus return_code switch (function) { case MODBUS_READ_COIL_1: rc = modbus_read_bits(ctx, reg_start, regs_to_read, tab_reg_bits); break; case MODBUS_READ_DINPUTS_2: rc = modbus_read_input_bits(ctx, reg_start, regs_to_read, tab_reg_bits); break; case MODBUS_READ_H_REGISTERS_3: rc = modbus_read_registers(ctx, reg_start, regs_to_read, tab_reg); break; case MODBUS_READ_I_REGISTERS_4: rc = modbus_read_input_registers(ctx, reg_start, regs_to_read, tab_reg); break; default : SET_MSG_RESULT(result, strdup("Check function (1,2,3,4) used")); //close connection modbus_close(ctx); if (lock_required == 1 ) UNLOCK_SERIAL_PORT; modbus_free(ctx); return SYSINFO_RET_FAIL; break; } //close connection modbus_close(ctx); if (lock_required == 1 ) UNLOCK_SERIAL_PORT; modbus_free(ctx); if (rc == -1) { SET_MSG_RESULT(result, strdup(modbus_strerror(errno))); return SYSINFO_RET_FAIL; } //post-parsing uint16_t temp_arr[2]; //output based on datatype switch(datatype){ case MODBUS_BIT: SET_UI64_RESULT(result, tab_reg_bits[0]); break; case MODBUS_INTEGER: SET_UI64_RESULT(result, tab_reg[0]); break; case MODBUS_FLOAT: if (end == MODBUS_16BIT_LE) { temp_arr[0] = tab_reg[0]; temp_arr[1] = tab_reg[1]; } if (end == MODBUS_16BIT_BE) { temp_arr[0] = tab_reg[1]; temp_arr[1] = tab_reg[0]; } SET_DBL_RESULT(result, modbus_get_float(temp_arr)); break; case MODBUS_LONG: //MODBUS_GET_INT32_FROM_INT16 is doing BIG_ENDIAN for register pair, so inverse registers (sort of hack) if (end == MODBUS_16BIT_LE) { temp_arr[0] = tab_reg[1]; temp_arr[1] = tab_reg[0]; } if (end == MODBUS_16BIT_BE) { temp_arr[0] = tab_reg[0]; temp_arr[1] = tab_reg[1]; } SET_UI64_RESULT(result, MODBUS_GET_INT32_FROM_INT16(temp_arr, 0)); break; default : SET_MSG_RESULT(result, strdup("Check datatype provided.")); modbus_free(ctx); return SYSINFO_RET_FAIL; break; } return SYSINFO_RET_OK; }
int main(int argc, char **argv) { uint8_t *tab_bit; uint16_t *tab_reg; /* Allocate and initialize the memory to store the status */ tab_bit = (uint8_t *)malloc(MODBUS_MAX_READ_BITS * sizeof(uint8_t)); memset(tab_bit, 0, MODBUS_MAX_READ_BITS * sizeof(uint8_t)); /* Allocate and initialize the memory to store the registers */ tab_reg = (uint16_t *)malloc(MODBUS_MAX_READ_REGISTERS * sizeof(uint16_t)); memset(tab_reg, 0, MODBUS_MAX_READ_REGISTERS * sizeof(uint16_t)); /* Defaults */ char host[1024] = "127.0.0.1"; size_t port = 502; enum mb_operations operation = read_registers; size_t base_addr = 0; // read from address 0 by deafult size_t n_addrs = 10; // read forst 10 addressxes by default. size_t n_times = 1; // one times by default. size_t interval = 0; // no waiting by default. bool quiet = false; // Do not suppress output by default. size_t n_data = 0; // The number of data items from the command line. char **data_items; // Array of data items from the command line. int c; int rc; while (1) { c = getopt(argc, argv, "h:p:o:b:a:n:i:q"); if (c == -1) break; switch (c) { case 'h': printf("Connect to host: '%s'\n", optarg); strncpy(host, optarg, 1024); // Made host str 1024. Should define a constant. break; case 'p': printf("Connect on port: '%s'\n", optarg); port = strtoul(optarg, (void *)0, 10); break; case 'o': printf("Option o with value '%s'\n", optarg); if (!strcmp("read_bits", optarg)) operation = read_bits; if (!strcmp("read_input_bits", optarg)) operation = read_input_bits; if (!strcmp("read_registers", optarg)) operation = read_registers; if (!strcmp("read_input_registers", optarg))operation = read_input_registers; if (!strcmp("write_bit", optarg)) operation = write_bit; if (!strcmp("write_register", optarg)) operation = write_register; if (!strcmp("write_bits", optarg)) operation = write_bits; if (!strcmp("write_registers",optarg)) operation = write_registers; break; case 'b': printf("Base address set to: '%s'\n", optarg); base_addr = strtoul(optarg, (void *)0, 10);; break; case 'a': printf("Number of addresses to read: '%s'\n", optarg); n_addrs = strtoul(optarg, (void *)0, 10); if (n_addrs > MODBUS_MAX_READ_REGISTERS) { printf("Number of addresses to read adjusted to maximum: '%i'\n", MODBUS_MAX_READ_REGISTERS); n_addrs = MODBUS_MAX_READ_REGISTERS; } break; case 'n': printf("Repeat this many times: '%s'\n", optarg); n_times = strtoul(optarg, (void *)0, 10); break; case 'i': printf("Repeat at this interval: '%s'\n", optarg); interval = strtoul(optarg, (void *)0, 10); break; case 'q': printf("option q: supressing output.\n"); quiet = true; break; case '?': printf("option ?: There is not doc only source codes.\n"); break; default: printf("?? getopt returned character code 0%o ??\n", c); } } if (optind < argc) { n_data = argc - optind; data_items = (char **)malloc(n_data * sizeof(char *)); printf("There are %i non-option ARGV-elements: ", (argc-optind)); size_t n = 0; while (optind < argc) { printf("%s ", argv[optind]); data_items[n] = argv[optind]; ++optind; ++n; } printf("\n"); } /* Get show on the road. */ modbus_t *ctx; ctx = modbus_new_tcp(host, port); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } for (size_t i = 0; i<n_times; i++) { switch (operation) { case read_bits: printf("READ BITS:\n"); rc = modbus_read_bits(ctx, base_addr, n_addrs, tab_bit); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } if (!quiet) { /* What did we read?*/ for (uint8_t *reg_ptr = tab_bit; reg_ptr < tab_bit + n_addrs; reg_ptr++) { printf("%i ", *reg_ptr); } printf("\n"); } break; case read_input_bits: printf("READ INPUT BITS:\n"); rc = modbus_read_input_bits(ctx, base_addr, n_addrs, tab_bit); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } if (!quiet) { /* What did we read?*/ for (uint8_t *reg_ptr = tab_bit; reg_ptr < tab_bit + n_addrs; reg_ptr++) { printf("%i ", *reg_ptr); } printf("\n"); } break; case read_registers: printf("READ REGISTERS:\n"); rc = modbus_read_registers(ctx, base_addr, n_addrs, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } if (!quiet) { /* What did we read?*/ for (uint16_t *reg_ptr = tab_reg; reg_ptr < tab_reg + n_addrs; reg_ptr++) { printf("%i ", *reg_ptr); } printf("\n"); } break; case read_input_registers: printf("READ INPUT REGISTERS\n\n"); rc = modbus_read_input_registers(ctx, base_addr, n_addrs, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } if (!quiet) { /* What did we read?*/ for (uint16_t *reg_ptr = tab_reg; reg_ptr < tab_reg + n_addrs; reg_ptr++) { printf("%i ", *reg_ptr); } printf("\n"); } break; case write_bit: printf("WRITE BIT\n"); n_addrs = 1; if (n_addrs > n_data) { fprintf(stderr, "Not enough data items on command line to write to requested address.\n"); return(EXIT_FAILURE); } for (uint8_t *reg_ptr = tab_bit; reg_ptr < tab_bit + n_addrs; reg_ptr++) { *reg_ptr = strtoul(*data_items++, (void *)0, 10); } rc = modbus_write_bit(ctx, base_addr, tab_bit); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } break; case write_register: printf("WRITE REGISTER\n"); // There is only one register. Almost everything else stays the same as write_registers. n_addrs = 1; if (n_addrs > n_data) { fprintf(stderr, "Not enough data items on command line to write to requested address.\n"); return(EXIT_FAILURE); } for (uint16_t *reg_ptr = tab_reg; reg_ptr < tab_reg + n_addrs; reg_ptr++) { *reg_ptr = strtoul(*data_items++, (void *)0, 10); } rc = modbus_write_register(ctx, base_addr, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } break; case write_bits: printf("WRITE BITS\n"); if (n_addrs > n_data) { fprintf(stderr, "Not enough data items on command line to write to requested addresses.\n"); return(EXIT_FAILURE); } for (uint8_t *reg_ptr = tab_bit; reg_ptr < tab_bit + n_addrs; reg_ptr++) { *reg_ptr = strtoul(*data_items++, (void *)0, 10); } rc = modbus_write_bits(ctx, base_addr, n_addrs, tab_bit); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } break; case write_registers: printf("WRITE REGISTERS\n"); if (n_addrs > n_data) { fprintf(stderr, "Not enough data items on command line to write to requested addresses.\n"); return(EXIT_FAILURE); } for (uint16_t *reg_ptr = tab_reg; reg_ptr < tab_reg + n_addrs; reg_ptr++) { *reg_ptr = strtoul(*data_items++, (void *)0, 10); } rc = modbus_write_registers(ctx, base_addr, n_addrs, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return(EXIT_FAILURE); } break; default: break; } sleep(interval); } /* Free the memory */ free(tab_bit); free(tab_reg); //free(data_items); /* Close the connection */ modbus_close(ctx); modbus_free(ctx); exit(EXIT_SUCCESS); }
void TDefaultModbusContext::ReadDisceteInputs(int addr, int nb, uint8_t *dest) { if (modbus_read_input_bits(InnerContext, addr, nb, dest) < nb) throw TModbusException("failed to read " + std::to_string(nb) + "discrete input(s) @ " + std::to_string(addr)); }