int readcoils(int initialaddress, int numberofcoils){ int rc; rc = modbus_read_bits(ctx,initialaddress,numberofcoils, coil_buffer); if (rc== -1){ fprintf(stderr, "%s\n", modbus_strerror(errno)); return 0; }else{ return 1; } }
/** * @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; }
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; }
int main(int argc, char **argv) { int c; int ok; int debug = 0; BackendParams *backend = 0; int slaveAddr = 1; int startAddr = 100; int startReferenceAt0 = 0; int readWriteNo = 1; int fType = FuncNone; int timeout_ms = 1000; int hasDevice = 0; int isWriteFunction = 0; enum WriteDataType { DataInt, Data8Array, Data16Array } wDataType = DataInt; union Data { int dataInt; uint8_t *data8; uint16_t *data16; } data; while (1) { int option_index = 0; static struct option long_options[] = { {DebugOpt, no_argument, 0, 0}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, "a:b:d:c:m:r:s:t:p:o:0", long_options, &option_index); if (c == -1) { break; } switch (c) { case 0: if (0 == strcmp(long_options[option_index].name, DebugOpt)) { debug = 1; } break; case 'a': { slaveAddr = getInt(optarg, &ok); if (0 == ok) { printf("Slave address (%s) is not integer!\n\n", optarg); printUsage(argv[0]); exit(EXIT_FAILURE); } } break; case 'c': { readWriteNo = getInt(optarg, &ok); if (0 == ok) { printf("# elements to read/write (%s) is not integer!\n\n", optarg); printUsage(argv[0]); exit(EXIT_FAILURE); } } break; case 'm': if (0 == strcmp(optarg, TcpOptVal)) { backend = createTcpBackend((TcpBackend*)malloc(sizeof(TcpBackend))); } else if (0 == strcmp(optarg, RtuOptVal)) backend = createRtuBackend((RtuBackend*)malloc(sizeof(RtuBackend))); else { printf("Unrecognized connection type %s\n\n", optarg); printUsage(argv[0]); exit(EXIT_FAILURE); } break; case 'r': { startAddr = getInt(optarg, &ok); if (0 == ok) { printf("Start address (%s) is not integer!\n\n", optarg); printUsage(argv[0]); exit(EXIT_FAILURE); } } break; case 't': { fType = getInt(optarg, &ok); if (0 == ok) { printf("Function type (%s) is not integer!\n\n", optarg); printUsage(argv[0]); exit(EXIT_FAILURE); } } break; case 'o': { timeout_ms = getInt(optarg, &ok); if (0 == ok) { printf("Timeout (%s) is not integer!\n\n", optarg); printUsage(argv[0]); exit(EXIT_FAILURE); } printf("Timeout set to %d\r\n", timeout_ms); } break; case '0': startReferenceAt0 = 1; break; //tcp/rtu params case 'p': case 'b': case 'd': case 's': if (0 == backend) { printf("Connection type (-m switch) has to be set before its params are provided!\n"); printUsage(argv[0]); exit(EXIT_FAILURE); } else { if (0 == backend->setParam(backend, c, optarg)) { printUsage(argv[0]); exit(EXIT_FAILURE); } } break; case '?': break; default: printf("?? getopt returned character code 0%o ??\n", c); } } if (0 == backend) { printf("No connection type was specified!\n"); printUsage(argv[0]); exit(EXIT_FAILURE); } if (1 == startReferenceAt0) { startAddr--; } //choose write data type switch (fType) { case(ReadCoils): wDataType = Data8Array; break; case(ReadDiscreteInput): wDataType = DataInt; break; case(ReadHoldingRegisters): case(ReadInputRegisters): wDataType = Data16Array; break; case(WriteSingleCoil): case(WriteSingleRegister): wDataType = DataInt; isWriteFunction = 1; break; case(WriteMultipleCoils): wDataType = Data8Array; isWriteFunction = 1; break; case(WriteMultipleRegisters): wDataType = Data16Array; isWriteFunction = 1; break; default: printf("No correct function type chosen"); printUsage(argv[0]); exit(EXIT_FAILURE); } if (isWriteFunction) { int dataNo = argc - optind - 1; /*if (-1 != readWriteNo && dataNo != readWriteNo) { printf("Write count specified, not equal to data values count!"); printUsage(argv[0]); exit(EXIT_FAILURE); } else*/ readWriteNo = dataNo; } //allocate buffer for data switch (wDataType) { case (DataInt): //no need to alloc anything break; case (Data8Array): data.data8 = malloc(readWriteNo * sizeof(uint8_t)); break; case (Data16Array): data.data16 = malloc(readWriteNo * sizeof(uint16_t)); break; default: printf("Data alloc error!\n"); exit(EXIT_FAILURE); } int wDataIdx = 0; if (1 == debug && 1 == isWriteFunction) printf("Data to write: "); if (optind < argc) { while (optind < argc) { if (0 == hasDevice) { if (0 != backend) { if (Rtu == backend->type) { RtuBackend *rtuP = (RtuBackend*)backend; strcpy(rtuP->devName, argv[optind]); hasDevice = 1; } else if (Tcp == backend->type) { TcpBackend *tcpP = (TcpBackend*)backend; strcpy(tcpP->ip, argv[optind]); hasDevice = 1; } } } else {//setting write data buffer switch (wDataType) { case (DataInt): data.dataInt = getInt(argv[optind], 0); if (debug) printf("0x%x", data.dataInt); break; case (Data8Array): { data.data8[wDataIdx] = getInt(argv[optind], 0); if (debug) printf("0x%02x ", data.data8[wDataIdx]); } break; case (Data16Array): { data.data16[wDataIdx] = getInt(argv[optind], 0); if (debug) printf("0x%04x ", data.data16[wDataIdx]); } break; } wDataIdx++; } optind++; } } if (1 == debug && 1 == isWriteFunction) printf("\n"); //create modbus context, and preapare it modbus_t *ctx = backend->createCtxt(backend); modbus_set_debug(ctx, debug); modbus_set_slave(ctx, slaveAddr); //issue the request int ret = -1; if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } else { switch (fType) { case(ReadCoils): ret = modbus_read_bits(ctx, startAddr, readWriteNo, data.data8); break; case(ReadDiscreteInput): printf("ReadDiscreteInput: not implemented yet!\n"); wDataType = DataInt; break; case(ReadHoldingRegisters): ret = modbus_read_registers(ctx, startAddr, readWriteNo, data.data16); break; case(ReadInputRegisters): ret = modbus_read_input_registers(ctx, startAddr, readWriteNo, data.data16); break; case(WriteSingleCoil): ret = modbus_write_bit(ctx, startAddr, data.dataInt); break; case(WriteSingleRegister): ret = modbus_write_register(ctx, startAddr, data.dataInt); break; case(WriteMultipleCoils): ret = modbus_write_bits(ctx, startAddr, readWriteNo, data.data8); break; case(WriteMultipleRegisters): ret = modbus_write_registers(ctx, startAddr, readWriteNo, data.data16); break; default: printf("No correct function type chosen"); printUsage(argv[0]); exit(EXIT_FAILURE); } } if (ret == readWriteNo) {//success if (isWriteFunction) printf("SUCCESS: written %d elements!\n", readWriteNo); else { printf("SUCCESS: read %d of elements:\n\tData: ", readWriteNo); int i = 0; if (DataInt == wDataType) { printf("0x%04x\n", data.dataInt); } else { const char Format8[] = "0x%02x "; const char Format16[] = "0x%04x "; const char *format = ((Data8Array == wDataType) ? Format8 : Format16); for (; i < readWriteNo; ++i) { printf(format, (Data8Array == wDataType) ? data.data8[i] : data.data16[i]); } printf("\n"); } } } else { printf("ERROR occured!\n"); modbus_strerror(errno); } //cleanup modbus_close(ctx); modbus_free(ctx); backend->del(backend); switch (wDataType) { case (DataInt): //nothing to be done break; case (Data8Array): free(data.data8); break; case (Data16Array): free(data.data16); break; } exit(EXIT_SUCCESS); }
/* Tests based on PI-MBUS-300 documentation */ int main(int argc, char *argv[]) { uint8_t *tab_bit; uint16_t *tab_reg; modbus_t *ctx; int i; int nb_points; double elapsed; uint32_t start; uint32_t end; uint32_t bytes; uint32_t rate; int rc; int n_loop; int use_backend; if (argc > 1) { if (strcmp(argv[1], "tcp") == 0) { use_backend = TCP; n_loop = 100000; } else if (strcmp(argv[1], "rtu") == 0) { use_backend = RTU; n_loop = 100; } else { printf("Usage:\n %s [tcp|rtu] - Modbus client to measure data bandwith\n\n", argv[0]); exit(1); } } else { /* By default */ use_backend = TCP; n_loop = 100000; } if (use_backend == TCP) { ctx = modbus_new_tcp("127.0.0.1", 1502); } else { ctx = modbus_new_rtu("/dev/ttyUSB1", 115200, 'N', 8, 1); modbus_set_slave(ctx, 1); } if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } /* 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)); printf("READ BITS\n\n"); nb_points = MODBUS_MAX_READ_BITS; start = gettime_ms(); for (i=0; i<n_loop; i++) { rc = modbus_read_bits(ctx, 0, nb_points, tab_bit); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } } end = gettime_ms(); elapsed = end - start; rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start); printf("Transfert rate in points/seconds:\n"); printf("* %d points/s\n", rate); printf("\n"); bytes = n_loop * (nb_points / 8) + ((nb_points % 8) ? 1 : 0); rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("Values:\n"); printf("* %d x %d values\n", n_loop, nb_points); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* TCP: Query and reponse header and values */ bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0); printf("Values and TCP Modbus overhead:\n"); printf("* %d x %d bytes\n", n_loop, bytes); bytes = n_loop * bytes; rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n\n"); printf("READ REGISTERS\n\n"); nb_points = MODBUS_MAX_READ_REGISTERS; start = gettime_ms(); for (i=0; i<n_loop; i++) { rc = modbus_read_registers(ctx, 0, nb_points, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } } end = gettime_ms(); elapsed = end - start; rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start); printf("Transfert rate in points/seconds:\n"); printf("* %d registers/s\n", rate); printf("\n"); bytes = n_loop * nb_points * sizeof(uint16_t); rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("Values:\n"); printf("* %d x %d values\n", n_loop, nb_points); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* TCP:Query and reponse header and values */ bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); printf("Values and TCP Modbus overhead:\n"); printf("* %d x %d bytes\n", n_loop, bytes); bytes = n_loop * bytes; rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n\n"); printf("READ AND WRITE REGISTERS\n\n"); nb_points = MODBUS_MAX_RW_WRITE_REGISTERS; start = gettime_ms(); for (i=0; i<n_loop; i++) { rc = modbus_read_and_write_registers(ctx, 0, nb_points, tab_reg, 0, nb_points, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } } end = gettime_ms(); elapsed = end - start; rate = (n_loop * nb_points) * G_MSEC_PER_SEC / (end - start); printf("Transfert rate in points/seconds:\n"); printf("* %d registers/s\n", rate); printf("\n"); bytes = n_loop * nb_points * sizeof(uint16_t); rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("Values:\n"); printf("* %d x %d values\n", n_loop, nb_points); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* TCP:Query and reponse header and values */ bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); printf("Values and TCP Modbus overhead:\n"); printf("* %d x %d bytes\n", n_loop, bytes); bytes = n_loop * bytes; rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* Free the memory */ free(tab_bit); free(tab_reg); /* Close the connection */ modbus_close(ctx); modbus_free(ctx); return 0; }
/****************************************************************************** * * * 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; }
/* At each loop, the program works in the range ADDRESS_START to * ADDRESS_END then ADDRESS_START + 1 to ADDRESS_END and so on. */ int main(void) { modbus_t *ctx; int rc; int nb_fail; int nb_loop; int addr; int nb; uint8_t *tab_rq_bits; uint8_t *tab_rp_bits; uint16_t *tab_rq_registers; uint16_t *tab_rw_rq_registers; uint16_t *tab_rp_registers; /* RTU */ /* ctx = modbus_new_rtu("/dev/ttyUSB0", 19200, 'N', 8, 1); modbus_set_slave(ctx, SERVER_ID); */ /* TCP */ ctx = modbus_new_tcp("127.0.0.1", 1502); modbus_set_debug(ctx, TRUE); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connection failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } /* Allocate and initialize the different memory spaces */ nb = ADDRESS_END - ADDRESS_START; tab_rq_bits = (uint8_t *) malloc(nb * sizeof(uint8_t)); memset(tab_rq_bits, 0, nb * sizeof(uint8_t)); tab_rp_bits = (uint8_t *) malloc(nb * sizeof(uint8_t)); memset(tab_rp_bits, 0, nb * sizeof(uint8_t)); tab_rq_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); memset(tab_rq_registers, 0, nb * sizeof(uint16_t)); tab_rp_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); memset(tab_rp_registers, 0, nb * sizeof(uint16_t)); tab_rw_rq_registers = (uint16_t *) malloc(nb * sizeof(uint16_t)); memset(tab_rw_rq_registers, 0, nb * sizeof(uint16_t)); nb_loop = nb_fail = 0; while (nb_loop++ < LOOP) { for (addr = ADDRESS_START; addr <= ADDRESS_END; addr++) { int i; /* Random numbers (short) */ for (i=0; i<nb; i++) { tab_rq_registers[i] = (uint16_t) (65535.0*rand() / (RAND_MAX + 1.0)); tab_rw_rq_registers[i] = ~tab_rq_registers[i]; tab_rq_bits[i] = tab_rq_registers[i] % 2; } nb = ADDRESS_END - addr; /* WRITE BIT */ rc = modbus_write_bit(ctx, addr, tab_rq_bits[0]); if (rc != 1) { printf("ERROR modbus_write_bit (%d)\n", rc); printf("Address = %d, value = %d\n", addr, tab_rq_bits[0]); nb_fail++; } else { rc = modbus_read_bits(ctx, addr, 1, tab_rp_bits); if (rc != 1 || tab_rq_bits[0] != tab_rp_bits[0]) { printf("ERROR modbus_read_bits single (%d)\n", rc); printf("address = %d\n", addr); nb_fail++; } } /* MULTIPLE BITS */ rc = modbus_write_bits(ctx, addr, nb, tab_rq_bits); if (rc != nb) { printf("ERROR modbus_write_bits (%d)\n", rc); printf("Address = %d, nb = %d\n", addr, nb); nb_fail++; } else { rc = modbus_read_bits(ctx, addr, nb, tab_rp_bits); if (rc != nb) { printf("ERROR modbus_read_bits\n"); printf("Address = %d, nb = %d\n", addr, nb); nb_fail++; } else { for (i=0; i<nb; i++) { if (tab_rp_bits[i] != tab_rq_bits[i]) { printf("ERROR modbus_read_bits\n"); printf("Address = %d, value %d (0x%X) != %d (0x%X)\n", addr, tab_rq_bits[i], tab_rq_bits[i], tab_rp_bits[i], tab_rp_bits[i]); nb_fail++; } } } } /* SINGLE REGISTER */ rc = modbus_write_register(ctx, addr, tab_rq_registers[0]); if (rc != 1) { printf("ERROR modbus_write_register (%d)\n", rc); printf("Address = %d, value = %d (0x%X)\n", addr, tab_rq_registers[0], tab_rq_registers[0]); nb_fail++; } else { rc = modbus_read_registers(ctx, addr, 1, tab_rp_registers); if (rc != 1) { printf("ERROR modbus_read_registers single (%d)\n", rc); printf("Address = %d\n", addr); nb_fail++; } else { if (tab_rq_registers[0] != tab_rp_registers[0]) { printf("ERROR modbus_read_registers single\n"); printf("Address = %d, value = %d (0x%X) != %d (0x%X)\n", addr, tab_rq_registers[0], tab_rq_registers[0], tab_rp_registers[0], tab_rp_registers[0]); nb_fail++; } } } /* MULTIPLE REGISTERS */ rc = modbus_write_registers(ctx, addr, nb, tab_rq_registers); if (rc != nb) { printf("ERROR modbus_write_registers (%d)\n", rc); printf("Address = %d, nb = %d\n", addr, nb); nb_fail++; } else { rc = modbus_read_registers(ctx, addr, nb, tab_rp_registers); if (rc != nb) { printf("ERROR modbus_read_registers (%d)\n", rc); printf("Address = %d, nb = %d\n", addr, nb); nb_fail++; } else { for (i=0; i<nb; i++) { if (tab_rq_registers[i] != tab_rp_registers[i]) { printf("ERROR modbus_read_registers\n"); printf("Address = %d, value %d (0x%X) != %d (0x%X)\n", addr, tab_rq_registers[i], tab_rq_registers[i], tab_rp_registers[i], tab_rp_registers[i]); nb_fail++; } } } } /* R/W MULTIPLE REGISTERS */ rc = modbus_write_and_read_registers(ctx, addr, nb, tab_rw_rq_registers, addr, nb, tab_rp_registers); if (rc != nb) { printf("ERROR modbus_read_and_write_registers (%d)\n", rc); printf("Address = %d, nb = %d\n", addr, nb); nb_fail++; } else { for (i=0; i<nb; i++) { if (tab_rp_registers[i] != tab_rw_rq_registers[i]) { printf("ERROR modbus_read_and_write_registers READ\n"); printf("Address = %d, value %d (0x%X) != %d (0x%X)\n", addr, tab_rp_registers[i], tab_rw_rq_registers[i], tab_rp_registers[i], tab_rw_rq_registers[i]); nb_fail++; } } rc = modbus_read_registers(ctx, addr, nb, tab_rp_registers); if (rc != nb) { printf("ERROR modbus_read_registers (%d)\n", rc); printf("Address = %d, nb = %d\n", addr, nb); nb_fail++; } else { for (i=0; i<nb; i++) { if (tab_rw_rq_registers[i] != tab_rp_registers[i]) { printf("ERROR modbus_read_and_write_registers WRITE\n"); printf("Address = %d, value %d (0x%X) != %d (0x%X)\n", addr, tab_rw_rq_registers[i], tab_rw_rq_registers[i], tab_rp_registers[i], tab_rp_registers[i]); nb_fail++; } } } } } printf("Test: "); if (nb_fail) printf("%d FAILS\n", nb_fail); else printf("SUCCESS\n"); } /* Free the memory */ free(tab_rq_bits); free(tab_rp_bits); free(tab_rq_registers); free(tab_rp_registers); /* Close the connection */ modbus_close(ctx); modbus_free(ctx); return 0; }
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::ReadCoils(int addr, int nb, uint8_t *dest) { if (modbus_read_bits(InnerContext, addr, nb, dest) < nb) throw TModbusException("failed to read " + std::to_string(nb) + " coil(s) @ " + std::to_string(addr)); }
int main(void) { uint8_t *tab_bit; uint16_t *tab_reg; modbus_t *ctx; int i; int nb_points; double elapsed; uint32_t start; uint32_t end; uint32_t bytes; uint32_t rate; int rc; /* TCP */ ctx = modbus_new_tcp("127.0.0.1", 1502); if (modbus_connect(ctx) == -1) { fprintf(stderr, "Connexion failed: %s\n", modbus_strerror(errno)); modbus_free(ctx); return -1; } /* 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)); printf("READ BITS\n\n"); nb_points = MODBUS_MAX_READ_BITS; start = gettime_ms(); for (i=0; i<NB_LOOPS; i++) { rc = modbus_read_bits(ctx, 0, nb_points, tab_bit); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } } end = gettime_ms(); elapsed = end - start; rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start); printf("Transfert rate in points/seconds:\n"); printf("* %d points/s\n", rate); printf("\n"); bytes = NB_LOOPS * (nb_points / 8) + ((nb_points % 8) ? 1 : 0); rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("Values:\n"); printf("* %d x %d values\n", NB_LOOPS, nb_points); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* TCP: Query and reponse header and values */ bytes = 12 + 9 + (nb_points / 8) + ((nb_points % 8) ? 1 : 0); printf("Values and TCP Modbus overhead:\n"); printf("* %d x %d bytes\n", NB_LOOPS, bytes); bytes = NB_LOOPS * bytes; rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n\n"); printf("READ REGISTERS\n\n"); nb_points = MODBUS_MAX_READ_REGISTERS; start = gettime_ms(); for (i=0; i<NB_LOOPS; i++) { rc = modbus_read_registers(ctx, 0, nb_points, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } } end = gettime_ms(); elapsed = end - start; rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start); printf("Transfert rate in points/seconds:\n"); printf("* %d registers/s\n", rate); printf("\n"); bytes = NB_LOOPS * nb_points * sizeof(uint16_t); rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("Values:\n"); printf("* %d x %d values\n", NB_LOOPS, nb_points); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* TCP:Query and reponse header and values */ bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); printf("Values and TCP Modbus overhead:\n"); printf("* %d x %d bytes\n", NB_LOOPS, bytes); bytes = NB_LOOPS * bytes; rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); printf("READ AND WRITE REGISTERS\n\n"); nb_points = MODBUS_MAX_RW_WRITE_REGISTERS; start = gettime_ms(); for (i=0; i<NB_LOOPS; i++) { rc = modbus_read_and_write_registers(ctx, 0, nb_points, tab_reg, 0, nb_points, tab_reg); if (rc == -1) { fprintf(stderr, "%s\n", modbus_strerror(errno)); return -1; } } end = gettime_ms(); elapsed = end - start; rate = (NB_LOOPS * nb_points) * G_MSEC_PER_SEC / (end - start); printf("Transfert rate in points/seconds:\n"); printf("* %d registers/s\n", rate); printf("\n"); bytes = NB_LOOPS * nb_points * sizeof(uint16_t); rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("Values:\n"); printf("* %d x %d values\n", NB_LOOPS, nb_points); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* TCP:Query and reponse header and values */ bytes = 12 + 9 + (nb_points * sizeof(uint16_t)); printf("Values and TCP Modbus overhead:\n"); printf("* %d x %d bytes\n", NB_LOOPS, bytes); bytes = NB_LOOPS * bytes; rate = bytes / 1024 * G_MSEC_PER_SEC / (end - start); printf("* %.3f ms for %d bytes\n", elapsed, bytes); printf("* %d KiB/s\n", rate); printf("\n"); /* Free the memory */ free(tab_bit); free(tab_reg); /* Close the connection */ modbus_close(ctx); modbus_free(ctx); return 0; }