Skip to main content

Database

In the bindings, use the Database class to manage the point values that the server exposes to clients. Despite the name, it's just an in-memory data structure protected by a mutex. The server answers reads from it, and passes writes to your WriteHandler.

note

The Rust interface does not provide a database. Your RequestHandler returns the values to read, which you would usually store in a Vec or HashMap.

Transactions​

All changes to the database are made inside a transaction, so a client request never sees a partially applied one. Start one on a running server with the update_database method, giving it the unit ID.

warning

A transaction holds the database's lock, which client requests also need, so keep transactions short and never block inside one.

Database initialization​

When adding a device to the DeviceMap, you also give it an initialization transaction. Use it to add the points, so that the server reports valid values as soon as it starts. A client that reads an address you haven't added gets an Illegal Data Address exception.

// POINT_COUNT points of each type, starting at index 0
void configure_db(rodbus_database_t *db, void *ctx)
{
for (uint16_t i = 0; i < POINT_COUNT; ++i) {
rodbus_database_add_coil(db, i, false);
rodbus_database_add_discrete_input(db, i, false);
rodbus_database_add_holding_register(db, i, 0);
rodbus_database_add_input_register(db, i, 0);
}
}

rodbus_device_map_t *map = rodbus_device_map_create();
rodbus_device_map_add_endpoint(map,
UNIT_ID, // unit id
get_write_handler(), // handler for write requests
(rodbus_database_callback_t){.callback = &configure_db} // callback for the initial state of the database
);

Updating points​

Update a point value by calling one of the update_xxx methods on the Database inside a transaction. The returned boolean indicates whether the point exists.

// runs while the database is locked, so client writes in between aren't lost
void toggle_coils(rodbus_database_t *db, void *ctx)
{
for (uint16_t i = 0; i < POINT_COUNT; ++i) {
bool value = false;
if (rodbus_database_get_coil(db, i, &value) == RODBUS_PARAM_ERROR_OK) {
rodbus_database_update_coil(db, i, !value);
}
}
}

rodbus_database_callback_t transaction = {.callback = &toggle_coils};
rodbus_param_error_t err = rodbus_server_update_database(server, UNIT_ID, transaction);

Getting point values​

You can also use the Database as a cache of the most recent values. Each type has a getter method to retrieve the most recently assigned value. Since the point may not be defined, the getters can fail. If you try to retrieve a point that doesn't exist using C++, Java or .NET, an exception is thrown.

Removing points​

Few applications need to remove points, but you can remove one from a running server. There is a type-specific function for removing every point type given its index. The returned boolean indicates whether the point existed.